diff --git a/Filelist b/Filelist index 2dbb2d3432..1f75741573 100644 --- a/Filelist +++ b/Filelist @@ -80,6 +80,7 @@ SRC_ALL = \ src/main.c \ src/map.c \ src/mark.c \ + src/match.c \ src/mbyte.c \ src/memfile.c \ src/memfile_test.c \ @@ -247,6 +248,7 @@ SRC_ALL = \ src/proto/main.pro \ src/proto/map.pro \ src/proto/mark.pro \ + src/proto/match.pro \ src/proto/mbyte.pro \ src/proto/memfile.pro \ src/proto/memline.pro \ diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index d1b7217248..7eaef20c14 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 Jun 17 +*eval.txt* For Vim version 8.2. Last change: 2020 Jun 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -157,7 +157,7 @@ You will not get an error if you try to change the type of a variable. 1.2 Function references ~ - *Funcref* *E695* *E718* + *Funcref* *E695* *E718* A Funcref variable is obtained with the |function()| function, the |funcref()| function or created with the lambda expression |expr-lambda|. It can be used in an expression in the place of a function name, before the parenthesis @@ -2523,13 +2523,15 @@ getjumplist([{winnr} [, {tabnr}]]) List list of jump list items getline({lnum}) String line {lnum} of current buffer getline({lnum}, {end}) List lines {lnum} to {end} of current buffer -getloclist({nr} [, {what}]) List list of location list items +getloclist({nr}) List list of location list items +getloclist({nr}, {what}) Dict get specific location list properties getmarklist([{expr}]) List list of global/local marks getmatches([{win}]) List list of current matches getmousepos() Dict last known mouse position getpid() Number process ID of Vim getpos({expr}) List position of cursor, mark, etc. -getqflist([{what}]) List list of quickfix items +getqflist() List list of quickfix items +getqflist({what}) Dict get specific quickfix list properties getreg([{regname} [, 1 [, {list}]]]) String or List contents of a register getreginfo([{regname}]) Dict information about a register @@ -2768,12 +2770,15 @@ setcmdpos({pos}) Number set cursor position in command-line setenv({name}, {val}) none set environment variable setfperm({fname}, {mode}) Number set {fname} file permissions to {mode} setline({lnum}, {line}) Number set line {lnum} to {line} -setloclist({nr}, {list} [, {action} [, {what}]]) - Number modify location list using {list} +setloclist({nr}, {list} [, {action}]) + Number modify location list using {list} +setloclist({nr}, {list}, {action}, {what}) + Number modify specific location list props setmatches({list} [, {win}]) Number restore a list of matches setpos({expr}, {list}) Number set the {expr} position to {list} -setqflist({list} [, {action} [, {what}]]) - Number modify quickfix list using {list} +setqflist({list} [, {action}]) Number modify quickfix list using {list} +setqflist({list}, {action}, {what}) + Number modify specific quickfix list props setreg({n}, {v} [, {opt}]) Number set register to value and type settabvar({nr}, {varname}, {val}) none set {varname} in tab page {nr} to {val} settabwinvar({tabnr}, {winnr}, {varname}, {val}) @@ -3647,7 +3652,7 @@ complete_check() *complete_check()* *complete_info()* complete_info([{what}]) - Returns a Dictionary with information about Insert mode + Returns a |Dictionary| with information about Insert mode completion. See |ins-completion|. The items are: mode Current completion mode name string. @@ -4874,7 +4879,7 @@ getbufinfo([{dict}]) Without an argument information about all the buffers is returned. - When the argument is a Dictionary only the buffers matching + When the argument is a |Dictionary| only the buffers matching the specified criteria are returned. The following keys can be specified in {dict}: buflisted include only listed buffers. @@ -5405,7 +5410,7 @@ getline({lnum} [, {end}]) < To get lines from another buffer see |getbufline()| getloclist({nr} [, {what}]) *getloclist()* - Returns a list with all the entries in the location list for + Returns a |List| with all the entries in the location list for window {nr}. {nr} can be the window number or the |window-ID|. When {nr} is zero the current window is used. @@ -5427,6 +5432,14 @@ getloclist({nr} [, {what}]) *getloclist()* |location-list-file-window| for more details. + Returns an empty Dictionary if there is no location list for + the window {nr} or the window is not present. + + Examples (See also |getqflist-examples|): > + :echo getloclist(3, {'all': 0}) + :echo getloclist(5, {'filewinid': 0}) + + getmarklist([{expr}] *getmarklist()* Without the {expr} argument returns a |List| with information about all the global marks. |mark| @@ -5471,7 +5484,7 @@ getmatches([{win}]) *getmatches()* :unlet m < getmousepos() *getmousepos()* - Returns a Dictionary with the last known position of the + Returns a |Dictionary| with the last known position of the mouse. This can be used in a mapping for a mouse click or in a filter of a popup window. The items are: screenrow screen row @@ -5691,12 +5704,12 @@ getregtype([{regname}]) *getregtype()* gettabinfo([{arg}]) *gettabinfo()* If {arg} is not specified, then information about all the tab - pages is returned as a List. Each List item is a Dictionary. + pages is returned as a |List|. Each List item is a |Dictionary|. Otherwise, {arg} specifies the tab page number and information about that one is returned. If the tab page does not exist an empty List is returned. - Each List item is a Dictionary with the following entries: + Each List item is a |Dictionary| with the following entries: tabnr tab page number. variables a reference to the dictionary with tabpage-local variables @@ -5724,7 +5737,7 @@ gettabwinvar({tabnr}, {winnr}, {varname} [, {def}]) *gettabwinvar()* When {varname} is empty a dictionary with all window-local variables is returned. When {varname} is equal to "&" get the values of all - window-local options in a Dictionary. + window-local options in a |Dictionary|. Otherwise, when {varname} starts with "&" get the value of a window-local option. Note that {varname} must be the name without "w:". @@ -5779,16 +5792,16 @@ gettagstack([{nr}]) *gettagstack()* GetWinnr()->gettagstack() getwininfo([{winid}]) *getwininfo()* - Returns information about windows as a List with Dictionaries. + Returns information about windows as a |List| with Dictionaries. If {winid} is given Information about the window with that ID - is returned, as a List with one item. If the window does not + is returned, as a |List| with one item. If the window does not exist the result is an empty list. Without {winid} information about all the windows in all the tab pages is returned. - Each List item is a Dictionary with the following entries: + Each List item is a |Dictionary| with the following entries: botline last displayed buffer line bufnr number of buffer in the window height window height (excluding winbar) @@ -5816,7 +5829,7 @@ getwininfo([{winid}]) *getwininfo()* GetWinnr()->getwininfo() getwinpos([{timeout}]) *getwinpos()* - The result is a List with two numbers, the result of + The result is a |List| with two numbers, the result of |getwinposx()| and |getwinposy()| combined: [x-pos, y-pos] {timeout} can be used to specify how long to wait in msec for @@ -5871,7 +5884,7 @@ glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) *glob()* 'suffixes' affect the ordering of matches. 'wildignorecase' always applies. - When {list} is present and it is |TRUE| the result is a List + When {list} is present and it is |TRUE| the result is a |List| with all matching files. The advantage of using a List is, you also get filenames containing newlines correctly. Otherwise the result is a String and when there are several @@ -5934,7 +5947,7 @@ globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]]) one of the patterns in 'wildignore' will be skipped and 'suffixes' affect the ordering of matches. - When {list} is present and it is |TRUE| the result is a List + When {list} is present and it is |TRUE| the result is a |List| with all matching files. The advantage of using a List is, you also get filenames containing newlines correctly. Otherwise the result is a String and when there are several matches, @@ -7293,7 +7306,7 @@ matchstrpos({expr}, {pat} [, {start} [, {count}]]) *matchstrpos()* *max()* max({expr}) Return the maximum value of all items in {expr}. - {expr} can be a List or a Dictionary. For a Dictionary, + {expr} can be a |List| or a |Dictionary|. For a Dictionary, it returns the maximum of all values in the Dictionary. If {expr} is neither a List nor a Dictionary, or one of the items in {expr} cannot be used as a Number this results in @@ -7364,7 +7377,7 @@ menu_info({name} [, {mode}]) *menu_info()* < *min()* min({expr}) Return the minimum value of all items in {expr}. - {expr} can be a List or a Dictionary. For a Dictionary, + {expr} can be a |List| or a |Dictionary|. For a Dictionary, it returns the minimum of all values in the Dictionary. If {expr} is neither a List nor a Dictionary, or one of the items in {expr} cannot be used as a Number this results in @@ -8026,7 +8039,7 @@ readdirex({directory} [, {expr} [, {dict}]]) *readdirex()* If {expr} results in 1 then this entry will be added to the list. The entries "." and ".." are always excluded. - Each time {expr} is evaluated |v:val| is set to a Dictionary + Each time {expr} is evaluated |v:val| is set to a |Dictionary| of the entry. When {expr} is a function the entry is passed as the argument. For example, to get a list of files ending in ".txt": > @@ -8275,7 +8288,7 @@ remove({list}, {idx} [, {end}]) *remove()* Without {end}: Remove the item at {idx} from |List| {list} and return the item. With {end}: Remove items from {idx} to {end} (inclusive) and - return a List with these items. When {idx} points to the same + return a |List| with these items. When {idx} points to the same item as {end} a list with one item is returned. When {end} points to an item before {idx} this is an error. See |list-index| for possible values of {idx} and {end}. @@ -8412,7 +8425,7 @@ screenchar({row}, {col}) *screenchar()* GetRow()->screenchar(col) screenchars({row}, {col}) *screenchars()* - The result is a List of Numbers. The first number is the same + The result is a |List| of Numbers. The first number is the same as what |screenchar()| returns. Further numbers are composing characters on top of the base character. This is mainly to be used for testing. @@ -8577,7 +8590,7 @@ searchcount([{options}]) *searchcount()* without the "S" flag in 'shortmess'. This works even if 'shortmess' does contain the "S" flag. - This returns a Dictionary. The dictionary is empty if the + This returns a |Dictionary|. The dictionary is empty if the previous pattern was not set and "pattern" was not specified. key type meaning ~ @@ -8659,7 +8672,7 @@ searchcount([{options}]) *searchcount()* " search again call searchcount() < - {options} must be a Dictionary. It can contain: + {options} must be a |Dictionary|. It can contain: key type meaning ~ recompute |Boolean| if |TRUE|, recompute the count like |n| or |N| was executed. @@ -9198,10 +9211,12 @@ setqflist({list} [, {action} [, {what}]]) *setqflist()* setreg({regname}, {value} [, {options}]) Set the register {regname} to {value}. If {regname} is "" or "@", the unnamed register '"' is used. + {value} may be any value returned by |getreg()| or |getreginfo()|, including a |List| or |Dict|. If {options} contains "a" or {regname} is upper case, then the value is appended. + {options} can also contain a register type specification: "c" or "v" |characterwise| mode "l" or "V" |linewise| mode @@ -9232,7 +9247,7 @@ setreg({regname}, {value} [, {options}]) register: > :let var_a = getreginfo() :call setreg('a', var_a) -< or: +< or: > :let var_a = getreg('a', 1, 1) :let var_amode = getregtype('a') .... @@ -9709,13 +9724,13 @@ state([{what}]) *state()* something is busy: m halfway a mapping, :normal command, feedkeys() or stuffed command - o operator pending or waiting for a command argument, - e.g. after |f| + o operator pending, e.g. after |d| a Insert mode autocomplete active x executing an autocommand w blocked on waiting, e.g. ch_evalexpr(), ch_read() and - ch_readraw() when reading json. - S not triggering SafeState or SafeStateAgain + ch_readraw() when reading json + S not triggering SafeState or SafeStateAgain, e.g. after + |f| or a count c callback invoked, including timer (repeats for recursiveness up to "ccc") s screen has scrolled for messages @@ -9896,7 +9911,7 @@ string({expr}) Return {expr} converted to a String. If {expr} is a Number, List [item, item] Dictionary {key: value, key: value} - When a List or Dictionary has a recursive reference it is + When a |List| or |Dictionary| has a recursive reference it is replaced by "[...]" or "{...}". Using eval() on the result will then fail. @@ -10187,7 +10202,7 @@ synIDtrans({synID}) *synIDtrans()* :echo synID(line("."), col("."), 1)->synIDtrans()->synIDattr("fg") synconcealed({lnum}, {col}) *synconcealed()* - The result is a List with currently three items: + The result is a |List| with currently three items: 1. The first item in the list is 0 if the character at the position {lnum} and {col} is not part of a concealable region, 1 if it is. @@ -10232,7 +10247,7 @@ synstack({lnum}, {col}) *synstack()* system({expr} [, {input}]) *system()* *E677* Get the output of the shell command {expr} as a string. See - |systemlist()| to get the output as a List. + |systemlist()| to get the output as a |List|. When {input} is given and is a string this string is written to a file and passed as stdin to the command. The string is @@ -10494,7 +10509,7 @@ timer_info([{id}]) returned. When {id} is omitted information about all timers is returned. - For each timer the information is stored in a Dictionary with + For each timer the information is stored in a |Dictionary| with these items: "id" the timer ID "time" time the timer was started with @@ -10728,7 +10743,7 @@ undotree() *undotree()* undo blocks. The first item in the "entries" list is the oldest undo item. - Each List item is a Dictionary with these items: + Each List item is a |Dictionary| with these items: "seq" Undo sequence number. Same as what appears in |:undolist|. "time" Timestamp when the change happened. Use @@ -10940,7 +10955,7 @@ win_splitmove({nr}, {target} [, {options}]) *win_splitmove()* Returns zero for success, non-zero for failure. - {options} is a Dictionary with the following optional entries: + {options} is a |Dictionary| with the following optional entries: "vertical" When TRUE, the split is created vertically, like with |:vsplit|. "rightbelow" When TRUE, the split is made below or to the @@ -12110,8 +12125,9 @@ An assignment leaves out the `:let` command. |vim9-declaration| text... text... {endmarker} - Set internal variable {var-name} to a List containing - the lines of text bounded by the string {endmarker}. + Set internal variable {var-name} to a |List| + containing the lines of text bounded by the string + {endmarker}. {endmarker} must not contain white space. {endmarker} cannot start with a lower case character. The last line should end only with the {endmarker} diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index 63e227d303..65a2d60430 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -1,4 +1,4 @@ -*if_lua.txt* For Vim version 8.2. Last change: 2020 May 17 +*if_lua.txt* For Vim version 8.2. Last change: 2020 Jun 28 VIM REFERENCE MANUAL by Luis Carvalho @@ -217,14 +217,27 @@ Vim's syntax for lists. Since lists are objects, changes in list references in Lua are reflected in Vim and vice-versa. A list "l" has the following properties and methods: +NOTE: In patch 8.2.1066 array indexes were changed from zero-based to +one-based. You can check with: > + if has("patch-8.2.1066") + Properties ---------- o "#l" is the number of items in list "l", equivalent to "len(l)" in Vim. - o "l[k]" returns the k-th item in "l"; "l" is zero-indexed, as in Vim. + o "l[k]" returns the k-th item in "l"; "l" is one-indexed, as in Lua. To modify the k-th item, simply do "l[k] = newitem"; in - particular, "l[k] = nil" removes the k-th item from "l". + particular, "l[k] = nil" removes the k-th item from "l". Item can + be added to the end of the list by "l[#l + 1] = newitem" o "l()" returns an iterator for "l". + o "table.insert(l, newitem)" inserts an item at the end of the list. + (only Lua 5.3 and later) + o "table.insert(l, position, newitem)" inserts an item at the + specified position. "position" is one-indexed. (only Lua 5.3 and + later) + o "table.remove(l, position)" removes an item at the specified + position. "position" is one-indexed. + Methods ------- @@ -237,13 +250,16 @@ Examples: :let l = [1, 'item'] :lua l = vim.eval('l') -- same 'l' :lua l:add(vim.list()) - :lua l[0] = math.pi + :lua l[1] = math.pi :echo l[0] " 3.141593 - :lua l[0] = nil -- remove first item + :lua l[1] = nil -- remove first item :lua l:insert(true, 1) - :lua print(l, #l, l[0], l[1], l[-1]) + :lua print(l, #l, l[1], l[2]) + :lua l[#l + 1] = 'value' + :lua table.insert(l, 100) + :lua table.insert(l, 2, 200) + :lua table.remove(l, 1) :lua for item in l() do print(item) end -< ============================================================================== 4. Dict userdata *lua-dict* @@ -333,6 +349,14 @@ Examples: :lua l = d.len -- assign d as 'self' :lua print(l()) < +Lua functions and closures are automatically converted to a Vim |Funcref| and +can be accessed in Vim scripts. Example: +> + lua < function ImStatusFunc() @@ -6879,7 +6879,7 @@ A jump table for the options with a short description can be found at |Q_op|. flag meaning when present ~ f use "(3 of 5)" instead of "(file 3 of 5)" i use "[noeol]" instead of "[Incomplete last line]" - l use "999L, 888C" instead of "999 lines, 888 characters" + l use "999L, 888B" instead of "999 lines, 888 bytes" m use "[+]" instead of "[Modified]" n use "[New]" instead of "[New File]" r use "[RO]" instead of "[readonly]" diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 58d09826b8..3e7e53746b 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -5018,7 +5018,7 @@ ctermul={color-nr} *highlight-ctermul* console. Example, for reverse video: > :highlight Visual ctermfg=bg ctermbg=fg < Note that the colors are used that are valid at the moment this - command are given. If the Normal group colors are changed later, the + command is given. If the Normal group colors are changed later, the "fg" and "bg" colors will not be adjusted. diff --git a/runtime/doc/tags b/runtime/doc/tags index e57ceae19b..507fa2479d 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -3948,6 +3948,7 @@ E103 diff.txt /*E103* E104 digraph.txt /*E104* E1042 vim9.txt /*E1042* E105 mbyte.txt /*E105* +E1050 vim9.txt /*E1050* E107 eval.txt /*E107* E108 eval.txt /*E108* E109 eval.txt /*E109* @@ -10136,6 +10137,7 @@ vim9-declaration vim9.txt /*vim9-declaration* vim9-declarations usr_46.txt /*vim9-declarations* vim9-differences vim9.txt /*vim9-differences* vim9-export vim9.txt /*vim9-export* +vim9-gotchas vim9.txt /*vim9-gotchas* vim9-import vim9.txt /*vim9-import* vim9-rationale vim9.txt /*vim9-rationale* vim9-scopes vim9.txt /*vim9-scopes* diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index c9716beb25..95cf7a40e9 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 Jun 21 +*todo.txt* For Vim version 8.2. Last change: 2020 Jun 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -40,12 +40,31 @@ browser use: https://github.com/vim/vim/issues/1234 Include src/po/vim.pot ? -See if resizing a terminal can be fixed. - Vim9 script: +- line continuation at script level: + eval_to_string_skip(), test with :throw + eval1_emsg(), pass "eap", test with :execute, :echomsg, :echoerr + handle_subscript() - call_func_rettv() - get_func_tv() + func( + args arg) + callers of get_func_tv(): + eval_func() + ex_call() + function arguments, test assert_equal() with lambda, test :function + :import: + others + eval_index() +- test: + [1, + 2, + 3]->Func() + Making everything work: +- "nr += 4" gives "already defined" error. - Error for "g:var: string = 'value'" - Make func()->append('$') work - value is last argument, not first. #6305 +- in Vim9 script expressions are evaluated differently, not using a type. + e.g. "'' == 0" does not give an error and evaluates to true. - possible memory leak in test_vim9_func through compile_nested_function. - memory leaks in test_vim9_expr - memory leaks in test_vim9_script @@ -134,12 +153,6 @@ Further improvements: - compile "expr" and "call" expression of a channel in channel_exe_cmd()? Popup windows: -- With some sequence get get hidden finished terminal buffer. (#5768) - Cannot close popup terminal (#5744) - Buffer can't be wiped, gets status "aF". (#5764) - Is buf->nwindows incorrect? -- popup_clear() and popup_close() should close the terminal popup, and - make the buffer hidden. #5745 - Cursor not updated before a redraw, making it jump. (#5943) - With terminal in popup, allow for popup_hide() to temporarily hide it.? - Fire some autocommand event after a new popup window was created and @@ -274,6 +287,13 @@ The buffer list and windows are locked, no changes possible How about removing Atari MiNT support? src/Make_mint.mak, src/os_mint.h, matches with __MINT__ +Add the <=> (spaceship) operator and "cond ?< expr ?= expr ?> expr" + replace this: + let left = GetLeftFunc() + let right = GetRightFunc() + let res = left < right ? lower : left == right ? equal : upper + by: + let res = GetLeftFunc() <=> GetRightFunc() ?< lower ?= equal ?> upper Patch to make :q work with local arglist. (Christian Brabandt, #6286) Patch to fix drawing error with DirectX. (James Grant, #5688) @@ -495,9 +515,6 @@ window 2. User expects 10 to be added to size of window 2. (Daniel Steinberg, Would be nice to set tab-local values for 'diffexpr' and 'diffopt'. Use t:diffexpr_option t:diffopt_option? (#4782) -v:register isn't reset early enough, may be used by next command. -(Andy Massimino, #5294, possible fix in #5305) - Internal diff doesn't handle binary file like external diff does. (Mike Williams, 2018 Oct 30) @@ -580,9 +597,6 @@ buffer didn't change at all. Line numbers in profile are off when function was defined with ":execute". (Daniel Hahler, #4511) -Add a way to create an empty, hidden buffer. Like doing ":new|hide". -":let buf = bufcreate('name') - Session file contains absolute paths when "curdir" is removed form 'sessionoptions', making it impossible to have a session with a relative path. (#4450) @@ -1199,8 +1213,8 @@ 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 named arguments for functions: - func Foo(start, count = 1 all = 1) +Implement named arguments for functions with optional arguments: + func Foo(start, count = 1, all = 1) call Foo(12, all = 0) Add a command to take a range of lines, filter them and put the output @@ -1393,8 +1407,6 @@ Did maintainer reply? ml_get errors when reloading file. (Chris Desjardins, 2016 Apr 19) Also with latest version. -Cannot delete a file with square brackets with delete(). (#696) - Completion for input() does not expand environment variables. (chdiza, 2016 Jul 25, #948) @@ -1403,8 +1415,6 @@ names, shell commands and the like. (Kikuchan, 2010 Oct 14) Assume the system converts between the actual encoding of the filesystem to the system encoding (usually utf-8). -'hlsearch' interferes with a Conceal match. (Rom Grk, 2016 Aug 9) - MS-Windows: use WS_HIDE instead of SW_SHOWMINNOACTIVE in os_win32.c? Otherwise task flickers in taskbar. @@ -1416,8 +1426,6 @@ Have a way to get the call stack, in a function and from an exception. Second problem in #966: ins_compl_add_tv() uses get_dict_string() multiple times, overwrites the one buffer. (Nikolay Pavlov, 2016 Aug 5) -Possibly wrong value for seq_cur. (Florent Fayolle, 2016 May 15, #806) - Filetype plugin for awk. (Doug Kearns, 2016 Sep 5) Patch to improve map documentation. Issue #799. @@ -1436,8 +1444,6 @@ Reject the value? #710. When doing "vi buf.md" a BufNew autocommand for *.md is not triggered. Because of using the initial buffer? (Dun Peal, 2016 May 12) -Add redrawtabline command. (Naruhiko Nishino, 2016 Jun 11) - Neovim patch for utfc_ptr2char_len() https://github.com/neovim/neovim/pull/4574 No test, needs some work to include. @@ -1507,20 +1513,10 @@ If ":bd" also closes a Tab page then the " mark is not set. (Harm te Hennepe, Patch to avoid redrawing tabline when the popup menu is visible. (Christian Brabandt, 2016 Jan 28) -Patch to show search statistics. (Christian Brabandt, 2016 Jul 22) - When the CursorMovedI event triggers, and CTRL-X was typed, a script cannot restore the mode properly. (Andrew Stewart, 2016 Apr 20) Do not trigger the event? -Using ":windo" to set options in all windows has the side effect that it -changes the window layout and the current window. Make a variant that saves -and restores. Use in the matchparen plugin. -Perhaps we can use ":windo {cmd}"? -Patch to add to :windo, :bufdo, etc. (Christian Brabandt, 2015 Jan -6, 2nd message) -Alternative: ":keeppos" command modifier: ":keeppos windo {cmd}". - Patch to fix display of listchars on the cursorline. (Nayuri Aohime, 2013) Update suggested by Yasuhiro Matsumoto, 2014 Nov 25: https://gist.github.com/presuku/d3d6b230b9b6dcfc0477 @@ -1549,10 +1545,6 @@ Python: ":py raw_input('prompt')" doesn't work. (Manu Hack) Comparing nested structures with "==" uses a different comparator than when comparing individual items. -Also, "'' == 0" evaluates to true, which isn't nice. -Add "===" to have a strict comparison (type and value match). -Add "==*" (?) to have a value match, but no automatic conversion, and v:true -equals 1 and 1.0, v:false equals 0 and 0.0.? Using uninitialized memory. (Dominique Pelle, 2015 Nov 4) @@ -1723,8 +1715,6 @@ arguments. Problem with transparent and matchgroup. Issue #475 -Patch to add :arglocal and :arglists. (Marcin Szamotulski, 2014 Aug 6) - Spell files use a latin single quote. Unicode also has another single quote: 0x2019. (Ron Aaron, 2014 Apr 4) New OpenOffice spell files support this with ICONV. But they are not @@ -1751,8 +1741,11 @@ from? Problem with upwards search on Windows (works OK on Linux). (Brett Stahlman, 2014 Jun 8) -Include a plugin manager with Vim? Neobundle seems to be the best currently. +Include a plugin manager with Vim? vim-plug seems to be the best currently: +https://github.com/junegunn/vim-plug. Also Vundle: https://github.com/gmarik/vundle +Or minpac: https://github.com/k-takata/minpac, since it leverages the builtin +package feature. Long message about this from ZyX, 2014 Mar 23. And following replies. Also see http://vim-wiki.mawercer.de/wiki/topic/vim%20plugin%20managment.html User view: @@ -1807,6 +1800,7 @@ instead. (Samuel Ferencik, 2013 Sep 28) Patch for XDG base directory support. (Jean François Bignolles, 2014 Mar 4) Remark on the docs. Should not be a compile time feature. But then what? +Also see #2034. Completion of ":e" is ":earlier", should be ":edit". Complete to the matching command instead of doing this alphabetically. (Mikel Jorgensen) @@ -1868,6 +1862,10 @@ Patch to add {lhs} to :mapclear: clear all maps starting with {lhs}. Exception caused by argument of return is not caught by try/catch. (David Barnett, 2013 Nov 19) +Bug in try/catch: return with invalid compare throws error that isn't caught. +(ZyX, 2011 Jan 26) +try/catch not working for argument of return. (Matt Wozniski, 2008 Sep 15) +try/catch not working when inside a for loop. (ZyX, 2011 Jan 25) Patch to fix that 'cedit' is recognized after :normal. (Christian Brabandt, 2013 Mar 19, later message) @@ -1903,6 +1901,8 @@ process that is running. It might actually be some other program, e.g. after a reboot. patch to add "combine" flag to syntax commands. (so8res, 2012 Dec 6) +Patch to add "combine" to :syntax, combines highlight attributes. (Nate +Soares, 2012 Dec 3) Syntax update problem in one buffer opened in two windows, bottom window is not correctly updated. (Paul Harris, 2012 Feb 27) @@ -2090,9 +2090,6 @@ doesn't jump to the correct line with :cfirst. (ZyX, 2011 Sep 18) Behavior of i" and a" text objects isn't logical. (Ben Fritz, 2013 Nov 19) -Bug in try/catch: return with invalid compare throws error that isn't caught. -(ZyX, 2011 Jan 26) - When setting a local option value from the global value, add a script ID that indicates this, so that ":verbose set" can give a hint. Check with options in the help file. @@ -2281,9 +2278,6 @@ Add local time at start of --startuptime output. Requires configure check for localtime(). Use format year-month-day hr:min:sec. -Patch to add "combine" to :syntax, combines highlight attributes. (Nate -Soares, 2012 Dec 3) - Patch to make ":hi link" also take arguments. (Nate Soares, 2012 Dec 4) Shell not recognized properly if it ends in "csh -f". (James Vega, 2009 Nov 3) @@ -2478,6 +2472,9 @@ Sergey Khorev) Consider making YankRing or something else that keeps a list of yanked text part of standard Vim. The "1 to "9 registers are not sufficient. +6 When yanking into the unnamed registers several times, somehow make the + previous contents also available (like it's done for deleting). What + register names to use? g"1, g"2, etc.? After doing "su" $HOME can be the old user's home, thus ~root/file is not correct. Don't use it in the swap file. @@ -2684,10 +2681,6 @@ Problem with 'ts' set to 9 and 'showbreak' to ">>>". (Matthew Winn, 2007 Oct In the swapfile dialog, add a H(elp) option that gives more info about what each choice does. Similar to ":help swap-exists-choices" -try/catch not working for argument of return. (Matt Wozniski, 2008 Sep 15) - -try/catch not working when inside a for loop. (ZyX, 2011 Jan 25) - ":tab help" always opens a new tab, while ":help" re-uses an existing window. Would be more consistent when an existing tab is re-used. (Tony Mechelynck) @@ -3257,7 +3250,7 @@ Quickfix/Location List: ":grep" and ":helpgrep". More generic solution: support a filter (e.g., by calling a function). 7 Add a command that goes back to the position from before jumping to the - first quickfix location. ":cbefore"? + first quickfix location. Vi incompatibility: - Try new POSIX tests, made after my comments. (Geoff Clare, 2005 April 7) @@ -3294,7 +3287,6 @@ Vi incompatibility: 7 The ":map" command output overwrites the command. Perhaps it should keep the ":map" when it's used without arguments? 7 CTRL-L is not the end of a section? It is for Posix! Make it an option. -7 Implement 'prompt' option. Init to off when stdin is not a tty. 7 Add a way to send an email for a crashed edit session. Create a file when making changes (containing name of the swap file), delete it when writing the file. Supply a program that can check for crashed sessions (either @@ -3472,8 +3464,6 @@ GUI: Solaris 2.6. (Marley) 9 On Solaris: Using a "-geometry" argument, bigger than the window where Vim is started from, causes empty lines below the cmdline. (raf) -8 X11 GUI: When menu is disabled by excluding 'm' from 'guioptions', ALT key - should not be used to trigger a menu (like the Win32 version). 8 When setting 'langmenu', it should be effective immediately. Store both the English and the translated text in the menu structure. Re-generate the translation when 'langmenu' has changed. @@ -3512,10 +3502,6 @@ GUI: When the "+0+0" is omitted it works. 8 When starting an external command, and 'guipty' set, BS and DEL are mixed up. Set erase character somehow? -8 A dead circumflex followed by a space should give the '^' character - (Rommel). Look how xterm does this. - Also: Bednar has some code for dead key handling. - Also: Nedit 5.0.2 with USE_XMIM does it right. (Gaya) 8 The compose key doesn't work properly (Cepas). Both for Win32 and X11. 7 The cursor in an inactive window should be hollow. Currently it's not visible. @@ -3612,17 +3598,8 @@ Macintosh: "Small" problems: -- Can't disable terminal flow control, to enable the use of CTRL-S and - CTRL-Q. Add an option for it? - When using e_secure in do_one_cmd() mention the command being executed, otherwise it's not clear where it comes from. -- When the quickfix window is open and executing ":echo 'hello'" using the - Command-line window, the text is immediately removed by the redrawing. - (Michael Henry, 2008 Nov 1) - Generic solution: When redrawing while there is a message on the - cmdline, don't erase the display but draw over the existing text. - Other solution, redraw after closing the cmdline window, before executing - the command. 9 For Turkish vim_tolower() and vim_toupper() also need to use utf_ functions for characters below 0x80. (Sertacyildiz) 9 When the last edited file is a help file, using '0 in a new Vim doesn't @@ -4082,8 +4059,6 @@ Spell checking: - Considering Hunspell 1.1.4: What does MAXNGRAMSUGS do? Is COMPLEXPREFIXES necessary when we have flags for affixes? -- Support spelling words in CamelCase as if they were two separate words. - Requires some option to enable it. (Timothy Knox) - There is no Finnish spell checking file. For openoffice Voikko is now used, which is based on Malaga: http://home.arcor.de/bjoern-beutel/malaga/ (Teemu Likonen) @@ -4458,8 +4433,6 @@ Vim script language: 7 Execute a function with standard option values. No need to save and restore option values. Especially useful for new options. Problem: how to avoid a performance penalty (esp. for string options)? -8 Add referring to key options with "&t_xx". Both for "echo &t_xx" and - ":let &t_xx =". Useful for making portable mappings. - range for ":exec", pass it on to the executed command. (Webb) 8 ":{range}source": source the lines from the current file. You can already yank lines and use :@" to execute them. @@ -4690,8 +4663,6 @@ Messages: - Delete message after new command has been entered and have waited for key. Perhaps after ten seconds? - Make message history available in "msg" variables: msg1, msg2, .. msg9. -8 When reading from stdin allow suppressing the "reading from stdin" - message. 9 Check handling of overwriting of messages and delays: Very wrong: errors while redrawing cause endless loop. When switching to another file and screen scrolls because of the long @@ -5979,9 +5950,6 @@ Registers: 8 Add put command that overwrites existing text. Should also work for blocks. Useful to move text around in a table. Works like using "R ^R r" for every line. -6 When yanking into the unnamed registers several times, somehow make the - previous contents also available (like it's done for deleting). What - register names to use? g"1, g"2, etc.? - When appending to a register, also report the total resulting number of lines. Or just say "99 more lines yanked", add the "more". - When inserting a register in Insert mode with CTRL-R, don't insert comment diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 21bc542a17..b14ff0b101 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 Jun 22 +*vim9.txt* For Vim version 8.2. Last change: 2020 Jun 24 VIM REFERENCE MANUAL by Bram Moolenaar @@ -378,6 +378,49 @@ string. > In Vim9 script one can use "true" for v:true and "false" for v:false. +What to watch out for ~ + *vim9-gotchas* +Vim9 was designed to be closer to often used programming languages, but at the +same time tries to support the legacy Vim commands. Some compromises had to +be made. Here is a summary of what might be unexpected. + +Ex command ranges need to be prefixed with a colon. > + -> " legacy Vim: shifts the previous line to the right + ->func() " Vim9: method call + :-> " Vim9: shifts the previous line to the right + + %s/a/b " legacy Vim: substitute on all lines + x = alongname + % another " Vim9: line continuation without a backslash + :%s/a/b " Vim9: substitute on all lines + +Functions defined with `:def` compile the whole function. Legacy functions +can bail out, and the following lines are not parsed: > + func Maybe() + if !has('feature') + return + endif + use-feature + endfunc +Vim9 functions are compiled as a whole: > + def Maybe() + if !has('feature') + return + endif + use-feature " May give compilation error + enddef +For a workaround, split it in two functions: > + func Maybe() + if has('feature') + call MaybyInner() + endif + endfunc + if has('feature') + def MaybeInner() + use-feature + enddef + endif + ============================================================================== 3. New style functions *fast-functions* diff --git a/runtime/filetype.vim b/runtime/filetype.vim index cd1c509d6e..7c76b12ee3 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 Jun 15 +" Last Change: 2020 Jun 25 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -542,7 +542,7 @@ au BufNewFile,BufRead *.ecd setf ecd au BufNewFile,BufRead *.e,*.E call dist#ft#FTe() " Elinks configuration -au BufNewFile,BufRead */etc/elinks.conf,*/.elinks/elinks.conf setf elinks +au BufNewFile,BufRead elinks.conf setf elinks " ERicsson LANGuage; Yaws is erlang too au BufNewFile,BufRead *.erl,*.hrl,*.yaws setf erlang @@ -1134,8 +1134,17 @@ au BufNewFile,BufRead *.ora setf ora " Packet filter conf au BufNewFile,BufRead pf.conf setf pf +" Pacman Config (close enough to dosini) +au BufNewFile,BufRead */etc/pacman.conf setf dosini + +" Pacman hooks +au BufNewFile,BufRead *.hook + \ if getline(1) == '[Trigger]' | + \ setf dosini | + \ endif + " Pam conf -au BufNewFile,BufRead */etc/pam.conf setf pamconf +au BufNewFile,BufRead */etc/pam.conf setf pamconf " Pam environment au BufNewFile,BufRead pam_env.conf,.pam_environment setf pamenv diff --git a/runtime/syntax/neomuttrc.vim b/runtime/syntax/neomuttrc.vim index 14852c1e1d..bd73de49ea 100644 --- a/runtime/syntax/neomuttrc.vim +++ b/runtime/syntax/neomuttrc.vim @@ -2,10 +2,10 @@ " Language: NeoMutt setup files " Maintainer: Richard Russon " Previous Maintainer: Guillaume Brogi -" Last Change: 2019-11-18 +" Last Change: 2020-06-21 " Original version based on syntax/muttrc.vim -" This file covers NeoMutt 2019-11-02 +" This file covers NeoMutt 2020-06-19 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -19,23 +19,22 @@ set cpo&vim setlocal isk=@,48-57,_,- " handling optional variables -syntax match muttrcComment "^# .*$" contains=@Spell -syntax match muttrcComment "^#[^ ].*$" -syntax match muttrcComment "^#$" -syntax match muttrcComment "[^\\]#.*$"lc=1 +syntax match muttrcComment "^# .*$" contains=@Spell +syntax match muttrcComment "^#[^ ].*$" +syntax match muttrcComment "^#$" +syntax match muttrcComment "[^\\]#.*$"lc=1 " Escape sequences (back-tick and pipe goes here too) -syntax match muttrcEscape +\\[#tnr"'Cc ]+ -syntax match muttrcEscape +[`|]+ -syntax match muttrcEscape +\\$+ +syntax match muttrcEscape +\\[#tnr"'Cc ]+ +syntax match muttrcEscape +[`|]+ +syntax match muttrcEscape +\\$+ " The variables takes the following arguments -"syn match muttrcString contained "=\s*[^ #"'`]\+"lc=1 contains=muttrcEscape -syntax region muttrcString contained keepend start=+"+ms=e skip=+\\"+ end=+"+ contains=muttrcEscape,muttrcCommand,muttrcAction,muttrcShellString -syntax region muttrcString contained keepend start=+'+ms=e skip=+\\'+ end=+'+ contains=muttrcEscape,muttrcCommand,muttrcAction +syntax region muttrcString contained keepend start=+"+ms=e skip=+\\"+ end=+"+ contains=muttrcEscape,muttrcCommand,muttrcAction,muttrcShellString +syntax region muttrcString contained keepend start=+'+ms=e skip=+\\'+ end=+'+ contains=muttrcEscape,muttrcCommand,muttrcAction syntax match muttrcStringNL contained skipwhite skipnl "\s*\\$" nextgroup=muttrcString,muttrcStringNL -syntax region muttrcShellString matchgroup=muttrcEscape keepend start=+`+ skip=+\\`+ end=+`+ contains=muttrcVarStr,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcCommand,muttrcVarDeprecatedStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad +syntax region muttrcShellString matchgroup=muttrcEscape keepend start=+`+ skip=+\\`+ end=+`+ contains=muttrcVarStr,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcCommand syntax match muttrcRXChars contained /[^\\][][.*?+]\+/hs=s+1 syntax match muttrcRXChars contained /[][|()][.*?+]*/ @@ -45,54 +44,53 @@ syntax match muttrcRXChars contained /\\/ " Why does muttrcRXString2 work with one \ when muttrcRXString requires two? syntax region muttrcRXString contained skipwhite start=+'+ skip=+\\'+ end=+'+ contains=muttrcRXChars syntax region muttrcRXString contained skipwhite start=+"+ skip=+\\"+ end=+"+ contains=muttrcRXChars -syntax region muttrcRXString contained skipwhite start=+[^ "'^]+ skip=+\\\s+ end=+\s+re=e-1 contains=muttrcRXChars +syntax region muttrcRXString contained skipwhite start=+[^ "'^]+ skip=+\\\s+ end=+\s+re=e-1 contains=muttrcRXChars " For some reason, skip refuses to match backslashes here... syntax region muttrcRXString contained matchgroup=muttrcRXChars skipwhite start=+\^+ end=+[^\\]\s+re=e-1 contains=muttrcRXChars syntax region muttrcRXString contained matchgroup=muttrcRXChars skipwhite start=+\^+ end=+$\s+ contains=muttrcRXChars syntax region muttrcRXString2 contained skipwhite start=+'+ skip=+\'+ end=+'+ contains=muttrcRXChars syntax region muttrcRXString2 contained skipwhite start=+"+ skip=+\"+ end=+"+ contains=muttrcRXChars -" these must be kept synchronized with muttrcRXString, but are intended for -" muttrcRXHooks +" these must be kept synchronized with muttrcRXString, but are intended for muttrcRXHooks syntax region muttrcRXHookString contained keepend skipwhite start=+'+ skip=+\\'+ end=+'+ contains=muttrcRXString nextgroup=muttrcString,muttrcStringNL syntax region muttrcRXHookString contained keepend skipwhite start=+"+ skip=+\\"+ end=+"+ contains=muttrcRXString nextgroup=muttrcString,muttrcStringNL -syntax region muttrcRXHookString contained keepend skipwhite start=+[^ "'^]+ skip=+\\\s+ end=+\s+re=e-1 contains=muttrcRXString nextgroup=muttrcString,muttrcStringNL +syntax region muttrcRXHookString contained keepend skipwhite start=+[^ "'^]+ skip=+\\\s+ end=+\s+re=e-1 contains=muttrcRXString nextgroup=muttrcString,muttrcStringNL syntax region muttrcRXHookString contained keepend skipwhite start=+\^+ end=+[^\\]\s+re=e-1 contains=muttrcRXString nextgroup=muttrcString,muttrcStringNL syntax region muttrcRXHookString contained keepend matchgroup=muttrcRXChars skipwhite start=+\^+ end=+$\s+ contains=muttrcRXString nextgroup=muttrcString,muttrcStringNL -syntax match muttrcRXHookStringNL contained skipwhite skipnl "\s*\\$" nextgroup=muttrcRXHookString,muttrcRXHookStringNL +syntax match muttrcRXHookStringNL contained skipwhite skipnl "\s*\\$" nextgroup=muttrcRXHookString,muttrcRXHookStringNL " these are exclusively for args lists (e.g. -rx pat pat pat ...) -syntax region muttrcRXPat contained keepend skipwhite start=+'+ skip=+\\'+ end=+'\s*+ contains=muttrcRXString nextgroup=muttrcRXPat -syntax region muttrcRXPat contained keepend skipwhite start=+"+ skip=+\\"+ end=+"\s*+ contains=muttrcRXString nextgroup=muttrcRXPat -syntax match muttrcRXPat contained /[^-'"#!]\S\+/ skipwhite contains=muttrcRXChars nextgroup=muttrcRXPat -syntax match muttrcRXDef contained "-rx\s\+" skipwhite nextgroup=muttrcRXPat +syntax region muttrcRXPat contained keepend skipwhite start=+'+ skip=+\\'+ end=+'\s*+ contains=muttrcRXString nextgroup=muttrcRXPat +syntax region muttrcRXPat contained keepend skipwhite start=+"+ skip=+\\"+ end=+"\s*+ contains=muttrcRXString nextgroup=muttrcRXPat +syntax match muttrcRXPat contained /[^-'"#!]\S\+/ skipwhite contains=muttrcRXChars nextgroup=muttrcRXPat +syntax match muttrcRXDef contained "-rx\s\+" skipwhite nextgroup=muttrcRXPat -syntax match muttrcSpecial +\(['"]\)!\1+ +syntax match muttrcSpecial +\(['"]\)!\1+ -syntax match muttrcSetStrAssignment contained skipwhite /=\s*\%(\\\?\$\)\?[0-9A-Za-z_-]\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr contains=muttrcVariable,muttrcEscapedVariable -syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*"+hs=s+1 end=+"+ skip=+\\"+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr contains=muttrcString -syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*'+hs=s+1 end=+'+ skip=+\\'+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr contains=muttrcString -syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr contains=muttrcVariable,muttrcEscapedVariable -syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetBoolAssignment contained skipwhite /=\s*"\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetBoolAssignment contained skipwhite /=\s*'\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr contains=muttrcVariable,muttrcEscapedVariable -syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\%(ask-\)\?\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetQuadAssignment contained skipwhite /=\s*"\%(ask-\)\?\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetQuadAssignment contained skipwhite /=\s*'\%(ask-\)\?\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetNumAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr contains=muttrcVariable,muttrcEscapedVariable -syntax match muttrcSetNumAssignment contained skipwhite /=\s*\d\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetNumAssignment contained skipwhite /=\s*"\d\+"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax match muttrcSetNumAssignment contained skipwhite /=\s*'\d\+'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax match muttrcSetStrAssignment contained skipwhite /=\s*\%(\\\?\$\)\?[0-9A-Za-z_-]\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable +syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*"+hs=s+1 end=+"+ skip=+\\"+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcString +syntax region muttrcSetStrAssignment contained skipwhite keepend start=+=\s*'+hs=s+1 end=+'+ skip=+\\'+ nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcString +syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable +syntax match muttrcSetBoolAssignment contained skipwhite /=\s*\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetBoolAssignment contained skipwhite /=\s*"\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetBoolAssignment contained skipwhite /=\s*'\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable +syntax match muttrcSetQuadAssignment contained skipwhite /=\s*\%(ask-\)\?\%(yes\|no\)/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetQuadAssignment contained skipwhite /=\s*"\%(ask-\)\?\%(yes\|no\)"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetQuadAssignment contained skipwhite /=\s*'\%(ask-\)\?\%(yes\|no\)'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetNumAssignment contained skipwhite /=\s*\\\?\$\w\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr contains=muttrcVariable,muttrcEscapedVariable +syntax match muttrcSetNumAssignment contained skipwhite /=\s*\d\+/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetNumAssignment contained skipwhite /=\s*"\d\+"/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax match muttrcSetNumAssignment contained skipwhite /=\s*'\d\+'/hs=s+1 nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr " Now catch some email addresses and headers (purified version from mail.vim) -syntax match muttrcEmail "[a-zA-Z0-9._-]\+@[a-zA-Z0-9./-]\+" -syntax match muttrcHeader "\<\c\%(From\|To\|C[Cc]\|B[Cc][Cc]\|Reply-To\|Subject\|Return-Path\|Received\|Date\|Replied\|Attach\)\>:\=" +syntax match muttrcEmail "[a-zA-Z0-9._-]\+@[a-zA-Z0-9./-]\+" +syntax match muttrcHeader "\<\c\%(From\|To\|C[Cc]\|B[Cc][Cc]\|Reply-To\|Subject\|Return-Path\|Received\|Date\|Replied\|Attach\)\>:\=" syntax match muttrcKeySpecial contained +\%(\\[Cc'"]\|\^\|\\[01]\d\{2}\)+ -syntax match muttrcKey contained "\S\+" contains=muttrcKeySpecial,muttrcKeyName -syntax region muttrcKey contained start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=muttrcKeySpecial,muttrcKeyName -syntax region muttrcKey contained start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=muttrcKeySpecial,muttrcKeyName +syntax match muttrcKey contained "\S\+" contains=muttrcKeySpecial,muttrcKeyName +syntax region muttrcKey contained start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=muttrcKeySpecial,muttrcKeyName +syntax region muttrcKey contained start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=muttrcKeySpecial,muttrcKeyName syntax match muttrcKeyName contained "\\[trne]" syntax match muttrcKeyName contained "\c<\%(BackSpace\|BackTab\|Delete\|Down\|End\|Enter\|Esc\|Home\|Insert\|Left\|Next\|PageDown\|PageUp\|Return\|Right\|Space\|Tab\|Up\)>" syntax match muttrcKeyName contained "\c" @@ -103,90 +101,84 @@ syntax match muttrcStrftimeEscapes contained /%[AaBbCcDdeFGgHhIjklMmnpRrSsTtUuVv syntax match muttrcStrftimeEscapes contained /%E[cCxXyY]/ syntax match muttrcStrftimeEscapes contained /%O[BdeHImMSuUVwWy]/ -syntax region muttrcIndexFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcIndexFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcGroupIndexFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcGroupIndexFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcSidebarFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcSidebarFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcQueryFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcQueryFormatEscapes,muttrcQueryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcAliasFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAliasFormatEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcAliasFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAliasFormatEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcAttachFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcAttachFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcComposeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcComposeFormatEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcComposeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcComposeFormatEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcFolderFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcFolderFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcMixFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcMixFormatEscapes,muttrcMixFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcMixFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcMixFormatEscapes,muttrcMixFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcPGPFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPGPFormatEscapes,muttrcPGPFormatConditionals,muttrcFormatErrors,muttrcPGPTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcPGPFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPGPFormatEscapes,muttrcPGPFormatConditionals,muttrcFormatErrors,muttrcPGPTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcPGPCmdFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPGPCmdFormatEscapes,muttrcPGPCmdFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcPGPCmdFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPGPCmdFormatEscapes,muttrcPGPCmdFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcStatusFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcStatusFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcPGPGetKeysFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPGPGetKeysFormatEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcPGPGetKeysFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPGPGetKeysFormatEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcSmimeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSmimeFormatEscapes,muttrcSmimeFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcSmimeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSmimeFormatEscapes,muttrcSmimeFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcStrftimeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -syntax region muttrcStrftimeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax region muttrcAliasFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAliasFormatEscapes,muttrcAliasFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcAliasFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAliasFormatEscapes,muttrcAliasFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcAttachFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcAttachFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcAttachFormatEscapes,muttrcAttachFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcComposeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcComposeFormatEscapes,muttrcComposeFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcComposeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcComposeFormatEscapes,muttrcComposeFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcFolderFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcFolderFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcFolderFormatEscapes,muttrcFolderFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcGroupIndexFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcGroupIndexFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcGroupIndexFormatEscapes,muttrcGroupIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcIndexFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcIndexFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcIndexFormatEscapes,muttrcIndexFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcMixFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcMixFormatEscapes,muttrcMixFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcMixFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcMixFormatEscapes,muttrcMixFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcPGPCmdFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPGPCmdFormatEscapes,muttrcPGPCmdFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcPGPCmdFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPGPCmdFormatEscapes,muttrcPGPCmdFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcPGPFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPGPFormatEscapes,muttrcPGPFormatConditionals,muttrcFormatErrors,muttrcPGPTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcPGPFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPGPFormatEscapes,muttrcPGPFormatConditionals,muttrcFormatErrors,muttrcPGPTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcQueryFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcQueryFormatEscapes,muttrcQueryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcQueryFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcQueryFormatEscapes,muttrcQueryFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcSidebarFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcSidebarFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSidebarFormatEscapes,muttrcSidebarFormatConditionals,muttrcFormatErrors,muttrcTimeEscapes nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcSmimeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcSmimeFormatEscapes,muttrcSmimeFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcSmimeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcSmimeFormatEscapes,muttrcSmimeFormatConditionals,muttrcVariable,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcStatusFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcStatusFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStatusFormatEscapes,muttrcStatusFormatConditionals,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcStrftimeFormatStr contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax region muttrcStrftimeFormatStr contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcStrftimeEscapes,muttrcFormatErrors nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr " Format escapes and conditionals syntax match muttrcFormatConditionals2 contained /[^?]*?/ -function! s:escapesConditionals(baseName, sequence, alignment, secondary) +function! s:escapesConditionals(baseName, sequence, padding, conditional) exec 'syntax match muttrc' . a:baseName . 'Escapes contained /%\%(\%(-\?[0-9]\+\)\?\%(\.[0-9]\+\)\?\)\?[:_]\?\%(' . a:sequence . '\|%\)/' - if a:alignment + if a:padding exec 'syntax match muttrc' . a:baseName . 'Escapes contained /%[>|*]./' endif - if a:secondary + if a:conditional exec 'syntax match muttrc' . a:baseName . 'Conditionals contained /%?\%(' . a:sequence . '\)?/ nextgroup=muttrcFormatConditionals2' else exec 'syntax match muttrc' . a:baseName . 'Conditionals contained /%?\%(' . a:sequence . '\)?/' endif endfunction -" CHECKED 2019-11-18 -" Ref: index_format_str() in hdrline.c -call s:escapesConditionals('IndexFormat', '[AaBbCDdEeFfgHIiJKLlMmNnOPqRrSsTtuvWXxYyZ(<[{]\|G[a-zA-Z]\+\|Fp\=\|z[cst]\|cr\=', 1, 1) -" Ref: alias_format_str() in addrbook.c -syntax match muttrcAliasFormatEscapes contained /%\%(\%(-\?[0-9]\+\)\?\%(\.[0-9]\+\)\?\)\?[:_]\?[afnrt%]/ -" Ref: group_index_format_str() in browser.c -call s:escapesConditionals('GroupIndexFormat', '[CdfMNns]', 1, 1) -" Ref: sidebar_format_str() in sidebar.c -call s:escapesConditionals('SidebarFormat', '[!BDdFLNnSt]', 1, 1) -" Ref: query_format_str() in query.c -call s:escapesConditionals('QueryFormat', '[acent]', 0, 1) +" CHECKED 2020-06-21 +" Ref: alias_format_str() in alias/dlgalias.c +call s:escapesConditionals('AliasFormat', '[acfnrt]', 1, 0) " Ref: attach_format_str() in recvattach.c call s:escapesConditionals('AttachFormat', '[CcDdeFfIMmnQsTtuX]', 1, 1) " Ref: compose_format_str() in compose.c -syntax match muttrcComposeFormatEscapes contained /%\%(\%(-\?[0-9]\+\)\?\%(\.[0-9]\+\)\?\)\?[:_]\?[ahlv%]/ -syntax match muttrcComposeFormatEscapes contained /%[>|*]./ +call s:escapesConditionals('ComposeFormat', '[ahlv]', 1, 1) " Ref: folder_format_str() in browser.c call s:escapesConditionals('FolderFormat', '[CDdFfgilmNnstu]', 1, 0) +" Ref: group_index_format_str() in browser.c +call s:escapesConditionals('GroupIndexFormat', '[CdfMNns]', 1, 1) +" Ref: index_format_str() in hdrline.c +call s:escapesConditionals('IndexFormat', '[AaBbCDdEefgHIiJKLlMmNnOPqRrSsTtuvWXxYyZ(<[{]\|@\i\+@\|G[a-zA-Z]\+\|Fp\=\|z[cst]\|cr\=', 1, 1) " Ref: mix_format_str() in remailer.c -call s:escapesConditionals('MixFormat', '[acns]', 0, 0) -" Ref: status_format_str() in status.c -call s:escapesConditionals('StatusFormat', '[bDdFfhLlMmnoPpRrSstuVv]', 1, 1) -" Ref: fmt_smime_command() in ncrypt/smime.c -call s:escapesConditionals('SmimeFormat', '[aCcdfiks]', 0, 1) +call s:escapesConditionals('MixFormat', '[acns]', 1, 0) +" Ref: pgp_command_format_str() in ncrypt/pgpinvoke.c +call s:escapesConditionals('PGPCmdFormat', '[afprs]', 0, 1) " Ref: crypt_format_str() in ncrypt/crypt_gpgme.c -" Ref: pgp_entry_fmt() in ncrypt/pgpkey.c +" Ref: pgp_entry_format_str() in ncrypt/pgpkey.c " Note: crypt_format_str() supports 'p', but pgp_entry_fmt() does not call s:escapesConditionals('PGPFormat', '[AaCcFfKkLlnptu[]', 0, 0) -" Ref: fmt_pgp_command() ncrypt/pgpinvoke.c -call s:escapesConditionals('PGPCmdFormat', '[afprs]', 0, 1) +" Ref: query_format_str() in alias/dlgquery.c +call s:escapesConditionals('QueryFormat', '[acent]', 1, 1) +" Ref: sidebar_format_str() in sidebar.c +call s:escapesConditionals('SidebarFormat', '[!BDdFLNnorStZ]', 1, 1) +" Ref: smime_command_format_str() in ncrypt/smime.c +call s:escapesConditionals('SmimeFormat', '[aCcdfiks]', 0, 1) +" Ref: status_format_str() in status.c +call s:escapesConditionals('StatusFormat', '[bDdFfhLlMmnoPpRrSstuVv]', 1, 1) -" This matches the documentation, but directly contradicts the code -" (according to the code, this should be identical to the muttrcPGPCmdFormatEscapes -syntax match muttrcPGPGetKeysFormatEscapes contained /%\%(\%(-\?[0-9]\+\)\?\%(\.[0-9]\+\)\?\)\?[:_]\?[acfklntu[%]/ - -syntax region muttrcTimeEscapes contained start=+%{+ end=+}+ contains=muttrcStrftimeEscapes -syntax region muttrcTimeEscapes contained start=+%\[+ end=+\]+ contains=muttrcStrftimeEscapes -syntax region muttrcTimeEscapes contained start=+%(+ end=+)+ contains=muttrcStrftimeEscapes -syntax region muttrcTimeEscapes contained start=+%<+ end=+>+ contains=muttrcStrftimeEscapes syntax region muttrcPGPTimeEscapes contained start=+%\[+ end=+\]+ contains=muttrcStrftimeEscapes +syntax region muttrcTimeEscapes contained start=+%(+ end=+)+ contains=muttrcStrftimeEscapes +syntax region muttrcTimeEscapes contained start=+%<+ end=+>+ contains=muttrcStrftimeEscapes +syntax region muttrcTimeEscapes contained start=+%\[+ end=+\]+ contains=muttrcStrftimeEscapes +syntax region muttrcTimeEscapes contained start=+%{+ end=+}+ contains=muttrcStrftimeEscapes syntax match muttrcVarEqualsAliasFmt contained skipwhite "=" nextgroup=muttrcAliasFormatStr syntax match muttrcVarEqualsAttachFmt contained skipwhite "=" nextgroup=muttrcAttachFormatStr @@ -197,29 +189,20 @@ syntax match muttrcVarEqualsIdxFmt contained skipwhite "=" nextgroup=mutt syntax match muttrcVarEqualsMixFmt contained skipwhite "=" nextgroup=muttrcMixFormatStr syntax match muttrcVarEqualsPGPCmdFmt contained skipwhite "=" nextgroup=muttrcPGPCmdFormatStr syntax match muttrcVarEqualsPGPFmt contained skipwhite "=" nextgroup=muttrcPGPFormatStr -syntax match muttrcVarEqualsPGPGetKeysFmt contained skipwhite "=" nextgroup=muttrcPGPGetKeysFormatStr syntax match muttrcVarEqualsQueryFmt contained skipwhite "=" nextgroup=muttrcQueryFormatStr syntax match muttrcVarEqualsSdbFmt contained skipwhite "=" nextgroup=muttrcSidebarFormatStr syntax match muttrcVarEqualsSmimeFmt contained skipwhite "=" nextgroup=muttrcSmimeFormatStr syntax match muttrcVarEqualsStatusFmt contained skipwhite "=" nextgroup=muttrcStatusFormatStr syntax match muttrcVarEqualsStrftimeFmt contained skipwhite "=" nextgroup=muttrcStrftimeFormatStr -syntax match muttrcVPrefix contained /[?&]/ nextgroup=muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax match muttrcVPrefix contained /[?&]/ nextgroup=muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " List of the different screens in mutt (see Menus in keymap.c) syntax keyword muttrcMenu contained alias attach browser compose editor generic index key_select_pgp key_select_smime mix pager pgp postpone query smime syntax match muttrcMenuList "\S\+" contained contains=muttrcMenu syntax match muttrcMenuCommas /,/ contained -" CHECKED 2019-11-02 -" List of hooks in Commands in init.h -syntax keyword muttrcHooks contained skipwhite - \ account-hook append-hook close-hook crypt-hook fcc-hook fcc-save-hook - \ folder-hook iconv-hook index-format-hook mbox-hook message-hook open-hook pgp-hook - \ reply-hook save-hook send-hook send2-hook -syntax keyword muttrcHooks skipwhite shutdown-hook startup-hook timeout-hook nextgroup=muttrcCommand - syntax region muttrcSpamPattern contained skipwhite keepend start=+'+ skip=+\\'+ end=+'+ contains=muttrcPattern nextgroup=muttrcString,muttrcStringNL syntax region muttrcSpamPattern contained skipwhite keepend start=+"+ skip=+\\"+ end=+"+ contains=muttrcPattern nextgroup=muttrcString,muttrcStringNL @@ -251,15 +234,19 @@ syntax match muttrcEscapedVariable contained "\\\$[a-zA-Z_-]\+" syntax match muttrcBadAction contained "[^<>]\+" contains=muttrcEmail syntax match muttrcAction contained "<[^>]\{-}>" contains=muttrcBadAction,muttrcFunction,muttrcKeyName +" CHECKED 2020-06-21 " First, functions that take regular expressions: syntax match muttrcRXHookNot contained /!\s*/ skipwhite nextgroup=muttrcRXHookString,muttrcRXHookStringNL syntax match muttrcRXHooks /\<\%(account\|append\|close\|crypt\|folder\|mbox\|open\|pgp\)-hook\>/ skipwhite nextgroup=muttrcRXHookNot,muttrcRXHookString,muttrcRXHookStringNL " Now, functions that take patterns syntax match muttrcPatHookNot contained /!\s*/ skipwhite nextgroup=muttrcPattern -syntax match muttrcPatHooks /\<\%(charset\|iconv\)-hook\>/ skipwhite nextgroup=muttrcPatHookNot,muttrcPattern +syntax match muttrcPatHooks /\<\%(charset\|iconv\|index-format\)-hook\>/ skipwhite nextgroup=muttrcPatHookNot,muttrcPattern syntax match muttrcPatHooks /\<\%(message\|reply\|send\|send2\|save\|fcc\|fcc-save\)-hook\>/ skipwhite nextgroup=muttrcPatHookNot,muttrcOptPattern +" Global hooks that take a command +syntax keyword muttrcHooks skipwhite shutdown-hook startup-hook timeout-hook nextgroup=muttrcCommand + syntax match muttrcBindFunction contained /\S\+\>/ skipwhite contains=muttrcFunction syntax match muttrcBindFunctionNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrcBindFunction,muttrcBindFunctionNL syntax match muttrcBindKey contained /\S\+/ skipwhite contains=muttrcKey nextgroup=muttrcBindFunction,muttrcBindFunctionNL @@ -272,8 +259,8 @@ syntax region muttrcMacroDescr contained keepend skipwhite start=+'+ms=e skip=+\ syntax region muttrcMacroDescr contained keepend skipwhite start=+"+ms=e skip=+\\"+ end=+"+me=s syntax match muttrcMacroDescrNL contained /\s*\\$/ skipwhite skipnl nextgroup=muttrcMacroDescr,muttrcMacroDescrNL syntax region muttrcMacroBody contained skipwhite start="\S" skip='\\ \|\\$' end=' \|$' contains=muttrcEscape,muttrcSet,muttrcUnset,muttrcReset,muttrcToggle,muttrcCommand,muttrcAction nextgroup=muttrcMacroDescr,muttrcMacroDescrNL -syntax region muttrcMacroBody matchgroup=Type contained skipwhite start=+'+ms=e skip=+\\'+ end=+'\|\%(\%(\\\\\)\@-][0-9]\+[kM]\?\|[0-9]\+[kM]\?[-]\%([0-9]\+[kM]\?\)\?\)" +" Parameter: date syntax match muttrcSimplePat contained "!\?\^\?[~][dr]\s*\%(\%(-\?[0-9]\{1,2}\%(/[0-9]\{1,2}\%(/[0-9]\{2}\%([0-9]\{2}\)\?\)\?\)\?\%([+*-][0-9]\+[ymwd]\)*\)\|\%(\%([0-9]\{1,2}\%(/[0-9]\{1,2}\%(/[0-9]\{2}\%([0-9]\{2}\)\?\)\?\)\?\%([+*-][0-9]\+[ymwd]\)*\)-\%([0-9]\{1,2}\%(/[0-9]\{1,2}\%(/[0-9]\{2}\%([0-9]\{2}\)\?\)\?\)\?\%([+*-][0-9]\+[ymwd]\)\?\)\?\)\|\%([<>=][0-9]\+[ymwd]\)\|\%(`[^`]\+`\)\|\%(\$[a-zA-Z0-9_-]\+\)\)" contains=muttrcShellString,muttrcVariable -syntax match muttrcSimplePat contained "!\?\^\?[~][bBcCefhHiLstxy]\s*" nextgroup=muttrcSimplePatRXContainer +" Parameter: regex +syntax match muttrcSimplePat contained "!\?\^\?[~][BbCcefHhIiLMstwxYy]\s*" nextgroup=muttrcSimplePatRXContainer +" Parameter: pattern syntax match muttrcSimplePat contained "!\?\^\?[%][bBcCefhHiLstxy]\s*" nextgroup=muttrcSimplePatString +" Parameter: pattern syntax match muttrcSimplePat contained "!\?\^\?[=][bcCefhHiLstxy]\s*" nextgroup=muttrcSimplePatString syntax region muttrcSimplePat contained keepend start=+!\?\^\?[~](+ end=+)+ contains=muttrcSimplePat + "syn match muttrcSimplePat contained /'[^~=%][^']*/ contains=muttrcRXString syntax region muttrcSimplePatString contained keepend start=+"+ end=+"+ skip=+\\"+ syntax region muttrcSimplePatString contained keepend start=+'+ end=+'+ skip=+\\'+ -syntax region muttrcSimplePatString contained keepend start=+[^ "']+ skip=+\\ + end=+\s+re=e-1 +syntax region muttrcSimplePatString contained keepend start=+[^ "']+ skip=+\\ + end=+\s+re=e-1 syntax region muttrcSimplePatRXContainer contained keepend start=+"+ end=+"+ skip=+\\"+ contains=muttrcRXString syntax region muttrcSimplePatRXContainer contained keepend start=+'+ end=+'+ skip=+\\'+ contains=muttrcRXString -syntax region muttrcSimplePatRXContainer contained keepend start=+[^ "']+ skip=+\\ + end=+\s+re=e-1 contains=muttrcRXString +syntax region muttrcSimplePatRXContainer contained keepend start=+[^ "']+ skip=+\\ + end=+\s+re=e-1 contains=muttrcRXString syntax match muttrcSimplePatMetas contained /[(|)]/ syntax match muttrcOptSimplePat contained skipwhite /[~=%!(^].*/ contains=muttrcSimplePat,muttrcSimplePatMetas @@ -350,12 +346,12 @@ syntax keyword muttrcColor contained brightblack brightblue brightcyan brightdef syntax match muttrcColor contained "\<\%(bright\)\=color\d\{1,3}\>" " Now for the structure of the color line syntax match muttrcColorRXNL contained skipnl "\s*\\$" nextgroup=muttrcColorRXPat,muttrcColorRXNL -syntax match muttrcColorBG contained /\s*[$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorRXPat,muttrcColorRXNL +syntax match muttrcColorBG contained /\s*[$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorRXPat,muttrcColorRXNL syntax match muttrcColorBGNL contained skipnl "\s*\\$" nextgroup=muttrcColorBG,muttrcColorBGNL -syntax match muttrcColorFG contained /\s*[$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorBG,muttrcColorBGNL +syntax match muttrcColorFG contained /\s*[$]\?\w\+/ contains=muttrcColor,muttrcVariable,muttrcUnHighlightSpace nextgroup=muttrcColorBG,muttrcColorBGNL syntax match muttrcColorFGNL contained skipnl "\s*\\$" nextgroup=muttrcColorFG,muttrcColorFGNL -syntax match muttrcColorContext contained /\s*[$]\?\w\+/ contains=muttrcColorField,muttrcVariable,muttrcUnHighlightSpace,muttrcColorCompose nextgroup=muttrcColorFG,muttrcColorFGNL -syntax match muttrcColorNL contained skipnl "\s*\\$" nextgroup=muttrcColorContext,muttrcColorNL,muttrcColorCompose +syntax match muttrcColorContext contained /\s*[$]\?\w\+/ contains=muttrcColorField,muttrcVariable,muttrcUnHighlightSpace,muttrcColorCompose nextgroup=muttrcColorFG,muttrcColorFGNL +syntax match muttrcColorNL contained skipnl "\s*\\$" nextgroup=muttrcColorContext,muttrcColorNL,muttrcColorCompose syntax match muttrcColorKeyword contained /^\s*color\s\+/ nextgroup=muttrcColorContext,muttrcColorNL,muttrcColorCompose " And now color's brother: syntax region muttrcUnColorPatterns contained skipwhite start=+\s*'+ end=+'+ skip=+\\'+ contains=muttrcPattern nextgroup=muttrcUnColorPatterns,muttrcUnColorPatNL @@ -373,25 +369,25 @@ syntax keyword muttrcMonoAttrib contained bold none normal reverse standout unde syntax keyword muttrcMono contained mono skipwhite nextgroup=muttrcColorField,muttrcColorCompose syntax match muttrcMonoLine "^\s*mono\s\+\S\+" skipwhite nextgroup=muttrcMonoAttrib contains=muttrcMono -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " List of fields in Fields in color.c syntax keyword muttrcColorField skipwhite contained - \ attachment attach_headers body bold error hdrdefault header index - \ index_author index_collapsed index_date index_flags index_label - \ index_number index_size index_subject index_tag index_tags indicator - \ markers message normal options progress prompt quoted search sidebar_divider - \ sidebar_flagged sidebar_highlight sidebar_indicator sidebar_new - \ sidebar_ordinary sidebar_spoolfile sidebar_unread signature status tilde tree - \ underline warning nextgroup=muttrcColor + \ attachment attach_headers body bold error hdrdefault header index index_author + \ index_collapsed index_date index_flags index_label index_number index_size index_subject + \ index_tag index_tags indicator markers message normal options progress prompt quoted + \ search sidebar_divider sidebar_flagged sidebar_highlight sidebar_indicator sidebar_new + \ sidebar_ordinary sidebar_spoolfile sidebar_unread signature status tilde tree underline + \ warning nextgroup=muttrcColor + syntax match muttrcColorField contained "\" syntax match muttrcColorCompose skipwhite contained /\s*compose\s*/ nextgroup=muttrcColorComposeField -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " List of fields in ComposeFields in color.c syntax keyword muttrcColorComposeField skipwhite contained - \ header security_both security_encrypt security_none security_sign - \ nextgroup=muttrcColorFG,muttrcColorFGNL + \ header security_both security_encrypt security_none security_sign + \ nextgroup=muttrcColorFG,muttrcColorFGNL syntax region muttrcColorLine keepend start=/^\s*color\s\+/ skip=+\\$+ end=+$+ contains=muttrcColorKeyword,muttrcComment,muttrcUnHighlightSpace function! s:boolQuadGen(type, vars, deprecated) @@ -403,674 +399,460 @@ function! s:boolQuadGen(type, vars, deprecated) let l:orig_type = copy(a:type) if a:deprecated let l:type = 'Deprecated' . a:type + exec 'syntax keyword muttrcVar' . l:type . ' ' . join(a:vars) + exec 'syntax keyword muttrcVar' . l:type . ' ' . join(l:novars) + exec 'syntax keyword muttrcVar' . l:type . ' ' . join(l:invvars) else let l:type = a:type + exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(a:vars) . ' nextgroup=muttrcSet' . l:orig_type . 'Assignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr' + exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:novars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr' + exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:invvars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr' endif - exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(a:vars) . ' nextgroup=muttrcSet' . l:orig_type . 'Assignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr' - exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:novars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr' - exec 'syntax keyword muttrcVar' . l:type . ' skipwhite contained ' . join(l:invvars) . ' nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr' endfunction -" CHECKED 2019-11-02 -" List of DT_BOOL in MuttVars in init.h +" CHECKED 2020-06-21 +" List of DT_BOOL in MuttVars in mutt_config.c call s:boolQuadGen('Bool', [ - \ 'allow_8bit', 'allow_ansi', 'arrow_cursor', 'ascii_chars', 'askbcc', - \ 'askcc', 'ask_follow_up', 'ask_x_comment_to', 'attach_split', 'autoedit', - \ 'auto_tag', 'beep', 'beep_new', 'bounce_delivered', 'braille_friendly', - \ 'change_folder_next', 'check_mbox_size', 'check_new', 'collapse_all', - \ 'collapse_flagged', 'collapse_unread', 'confirmappend', 'confirmcreate', - \ 'crypt_autoencrypt', 'crypt_autopgp', 'crypt_autosign', 'crypt_autosmime', - \ 'crypt_confirmhook', 'crypt_opportunistic_encrypt', 'crypt_replyencrypt', - \ 'crypt_replysign', 'crypt_replysignencrypted', 'crypt_timestamp', - \ 'crypt_use_gpgme', 'crypt_use_pka', 'delete_untag', 'digest_collapse', - \ 'duplicate_threads', 'edit_headers', 'encode_from', 'fast_reply', - \ 'fcc_clear', 'flag_safe', 'followup_to', 'force_name', 'forward_decode', - \ 'forward_decrypt', 'forward_quote', 'forward_references', 'hdrs', - \ 'header', 'header_cache_compress', 'header_color_partial', 'help', - \ 'hidden_host', 'hide_limited', 'hide_missing', 'hide_thread_subject', - \ 'hide_top_limited', 'hide_top_missing', 'history_remove_dups', - \ 'honor_disposition', 'idn_decode', 'idn_encode', 'ignore_list_reply_to', - \ 'imap_check_subscribed', 'imap_idle', 'imap_list_subscribed', - \ 'imap_passive', 'imap_peek', 'imap_servernoise', 'implicit_autoview', - \ 'include_onlyfirst', 'keep_flagged', 'mailcap_sanitize', - \ 'maildir_check_cur', 'maildir_header_cache_verify', 'maildir_trash', - \ 'mail_check_recent', 'mail_check_stats', 'markers', 'mark_old', - \ 'menu_move_off', 'menu_scroll', 'message_cache_clean', 'meta_key', - \ 'metoo', 'mh_purge', 'mime_forward_decode', 'mime_subject', - \ 'mime_type_query_first', 'narrow_tree', 'nm_record', 'nntp_listgroup', - \ 'nntp_load_description', 'pager_stop', 'pgp_autoinline', - \ 'pgp_auto_decode', 'pgp_check_exit', 'pgp_ignore_subkeys', 'pgp_long_ids', - \ 'pgp_replyinline', 'pgp_retainable_sigs', 'pgp_self_encrypt', - \ 'pgp_show_unusable', 'pgp_strict_enc', 'pgp_use_gpg_agent', 'pipe_decode', - \ 'pipe_split', 'pop_auth_try_all', 'pop_last', 'postpone_encrypt', - \ 'print_decode', 'print_split', 'prompt_after', 'read_only', - \ 'reflow_space_quotes', 'reflow_text', 'reply_self', 'reply_with_xorig', - \ 'resolve', 'resume_draft_files', 'resume_edited_draft_files', - \ 'reverse_alias', 'reverse_name', 'reverse_realname', 'rfc2047_parameters', - \ 'save_address', 'save_empty', 'save_name', 'save_unsubscribed', 'score', - \ 'show_new_news', 'show_only_unread', 'sidebar_folder_indent', - \ 'sidebar_new_mail_only', 'sidebar_next_new_wrap', 'sidebar_on_right', - \ 'sidebar_short_path', 'sidebar_visible', 'sig_dashes', 'sig_on_top', - \ 'smart_wrap', 'smime_ask_cert_label', 'smime_decrypt_use_default_key', - \ 'smime_is_default', 'smime_self_encrypt', 'sort_re', 'ssl_force_tls', - \ 'ssl_usesystemcerts', 'ssl_use_sslv2', 'ssl_use_sslv3', 'ssl_use_tlsv1', - \ 'ssl_use_tlsv1_1', 'ssl_use_tlsv1_2', 'ssl_verify_dates', - \ 'ssl_verify_host', 'ssl_verify_partial_chains', 'status_on_top', - \ 'strict_threads', 'suspend', 'text_flowed', 'thorough_search', - \ 'thread_received', 'tilde', 'ts_enabled', 'uncollapse_jump', - \ 'uncollapse_new', 'user_agent', 'use_8bitmime', 'use_domain', - \ 'use_envelope_from', 'use_from', 'use_ipv6', 'virtual_spoolfile', - \ 'wait_key', 'weed', 'wrap_search', 'write_bcc', 'x_comment_to', - \ 'attach_save_without_prompting', 'autocrypt', 'autocrypt_reply', - \ 'auto_subscribe', 'browser_abbreviate_mailboxes', - \ 'crypt_protected_headers_read', 'crypt_protected_headers_save', - \ 'crypt_protected_headers_write', 'fcc_before_send', 'imap_condstore', - \ 'imap_qresync', 'imap_rfc5161', 'include_encrypted', - \ 'pgp_check_gpg_decrypt_status_fd', 'sidebar_non_empty_mailbox_only', - \ 'size_show_bytes', 'size_show_fractions', 'size_show_mb', - \ 'size_units_on_left', 'ssl_use_tlsv1_3' - \ ], 0) + \ 'abort_backspace', 'allow_8bit', 'allow_ansi', 'arrow_cursor', 'ascii_chars', 'askbcc', + \ 'askcc', 'ask_follow_up', 'ask_x_comment_to', 'attach_save_without_prompting', + \ 'attach_split', 'autocrypt', 'autocrypt_reply', 'autoedit', 'auto_subscribe', 'auto_tag', + \ 'beep', 'beep_new', 'bounce_delivered', 'braille_friendly', + \ 'browser_abbreviate_mailboxes', 'change_folder_next', 'check_mbox_size', 'check_new', + \ 'collapse_all', 'collapse_flagged', 'collapse_unread', 'confirmappend', 'confirmcreate', + \ 'crypt_autoencrypt', 'crypt_autopgp', 'crypt_autosign', 'crypt_autosmime', + \ 'crypt_confirmhook', 'crypt_opportunistic_encrypt', + \ 'crypt_opportunistic_encrypt_strong_keys', 'crypt_protected_headers_read', + \ 'crypt_protected_headers_save', 'crypt_protected_headers_write', 'crypt_replyencrypt', + \ 'crypt_replysign', 'crypt_replysignencrypted', 'crypt_timestamp', 'crypt_use_gpgme', + \ 'crypt_use_pka', 'delete_untag', 'digest_collapse', 'duplicate_threads', 'edit_headers', + \ 'encode_from', 'fast_reply', 'fcc_before_send', 'fcc_clear', 'flag_safe', 'followup_to', + \ 'force_name', 'forward_decode', 'forward_decrypt', 'forward_quote', 'forward_references', + \ 'hdrs', 'header', 'header_color_partial', 'help', 'hidden_host', 'hide_limited', + \ 'hide_missing', 'hide_thread_subject', 'hide_top_limited', 'hide_top_missing', + \ 'history_remove_dups', 'honor_disposition', 'idn_decode', 'idn_encode', + \ 'ignore_list_reply_to', 'imap_check_subscribed', 'imap_condstore', 'imap_deflate', + \ 'imap_idle', 'imap_list_subscribed', 'imap_passive', 'imap_peek', 'imap_qresync', + \ 'imap_rfc5161', 'imap_servernoise', 'implicit_autoview', 'include_encrypted', + \ 'include_onlyfirst', 'keep_flagged', 'mailcap_sanitize', 'maildir_check_cur', + \ 'maildir_header_cache_verify', 'maildir_trash', 'mail_check_recent', 'mail_check_stats', + \ 'markers', 'mark_old', 'menu_move_off', 'menu_scroll', 'message_cache_clean', 'meta_key', + \ 'metoo', 'mh_purge', 'mime_forward_decode', 'mime_subject', 'mime_type_query_first', + \ 'narrow_tree', 'nm_record', 'nntp_listgroup', 'nntp_load_description', 'pager_stop', + \ 'pgp_autoinline', 'pgp_auto_decode', 'pgp_check_exit', 'pgp_check_gpg_decrypt_status_fd', + \ 'pgp_ignore_subkeys', 'pgp_long_ids', 'pgp_replyinline', 'pgp_retainable_sigs', + \ 'pgp_self_encrypt', 'pgp_show_unusable', 'pgp_strict_enc', 'pgp_use_gpg_agent', + \ 'pipe_decode', 'pipe_split', 'pop_auth_try_all', 'pop_last', 'postpone_encrypt', + \ 'print_decode', 'print_split', 'prompt_after', 'read_only', 'reflow_space_quotes', + \ 'reflow_text', 'reply_self', 'reply_with_xorig', 'resolve', 'resume_draft_files', + \ 'resume_edited_draft_files', 'reverse_alias', 'reverse_name', 'reverse_realname', + \ 'rfc2047_parameters', 'save_address', 'save_empty', 'save_name', 'save_unsubscribed', + \ 'score', 'show_new_news', 'show_only_unread', 'sidebar_folder_indent', + \ 'sidebar_new_mail_only', 'sidebar_next_new_wrap', 'sidebar_non_empty_mailbox_only', + \ 'sidebar_on_right', 'sidebar_short_path', 'sidebar_visible', 'sig_dashes', 'sig_on_top', + \ 'size_show_bytes', 'size_show_fractions', 'size_show_mb', 'size_units_on_left', + \ 'smart_wrap', 'smime_ask_cert_label', 'smime_decrypt_use_default_key', 'smime_is_default', + \ 'smime_self_encrypt', 'sort_re', 'ssl_force_tls', 'ssl_usesystemcerts', 'ssl_use_sslv2', + \ 'ssl_use_sslv3', 'ssl_use_tlsv1', 'ssl_use_tlsv1_1', 'ssl_use_tlsv1_2', 'ssl_use_tlsv1_3', + \ 'ssl_verify_dates', 'ssl_verify_host', 'ssl_verify_partial_chains', 'status_on_top', + \ 'strict_threads', 'suspend', 'text_flowed', 'thorough_search', 'thread_received', 'tilde', + \ 'ts_enabled', 'uncollapse_jump', 'uncollapse_new', 'user_agent', 'use_8bitmime', + \ 'use_domain', 'use_envelope_from', 'use_from', 'use_ipv6', 'virtual_spoolfile', + \ 'wait_key', 'weed', 'wrap_search', 'write_bcc', 'x_comment_to' + \ ], 0) -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " Deprecated Bools -" List of DT_SYNONYM synonyms of Bools in MuttVars in init.h +" List of DT_SYNONYM or DT_DEPRECATED Bools in MuttVars in mutt_config.c call s:boolQuadGen('Bool', [ - \ 'edit_hdrs', 'envelope_from', 'forw_decode', 'forw_decrypt', - \ 'forw_quote', 'ignore_linear_white_space', 'pgp_autoencrypt', - \ 'pgp_autosign', 'pgp_auto_traditional', 'pgp_create_traditional', - \ 'pgp_replyencrypt', 'pgp_replysign', 'pgp_replysignencrypted', - \ 'xterm_set_titles' - \ ], 1) + \ 'edit_hdrs', 'envelope_from', 'forw_decode', 'forw_decrypt', 'forw_quote', + \ 'header_cache_compress', 'ignore_linear_white_space', 'pgp_autoencrypt', 'pgp_autosign', + \ 'pgp_auto_traditional', 'pgp_create_traditional', 'pgp_replyencrypt', 'pgp_replysign', + \ 'pgp_replysignencrypted', 'xterm_set_titles' + \ ], 1) -" CHECKED 2019-11-02 -" List of DT_QUAD in MuttVars in init.h +" CHECKED 2020-06-21 +" List of DT_QUAD in MuttVars in mutt_config.c call s:boolQuadGen('Quad', [ - \ 'abort_noattach', 'abort_nosubject', 'abort_unmodified', 'bounce', - \ 'catchup_newsgroup', 'copy', 'crypt_verify_sig', 'delete', 'fcc_attach', - \ 'followup_to_poster', 'forward_edit', 'honor_followup_to', 'include', - \ 'mime_forward', 'mime_forward_rest', 'move', 'pgp_mime_auto', - \ 'pop_delete', 'pop_reconnect', 'postpone', 'post_moderated', 'print', - \ 'quit', 'recall', 'reply_to', 'ssl_starttls', 'forward_attachments' - \ ], 0) + \ 'abort_noattach', 'abort_nosubject', 'abort_unmodified', 'bounce', 'catchup_newsgroup', + \ 'copy', 'crypt_verify_sig', 'delete', 'fcc_attach', 'followup_to_poster', + \ 'forward_attachments', 'forward_edit', 'honor_followup_to', 'include', 'mime_forward', + \ 'mime_forward_rest', 'move', 'pgp_mime_auto', 'pop_delete', 'pop_reconnect', 'postpone', + \ 'post_moderated', 'print', 'quit', 'recall', 'reply_to', 'ssl_starttls', + \ ], 0) -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " Deprecated Quads -" List of DT_SYNONYM synonyms of Quads in MuttVars in init.h +" List of DT_SYNONYM or DT_DEPRECATED Quads in MuttVars in mutt_config.c call s:boolQuadGen('Quad', [ - \ 'mime_fwd', 'pgp_encrypt_self', 'pgp_verify_sig', 'smime_encrypt_self' - \ ], 1) + \ 'mime_fwd', 'pgp_encrypt_self', 'pgp_verify_sig', 'smime_encrypt_self' + \ ], 1) -" CHECKED 2019-11-02 -" List of DT_NUMBER or DT_LONG in MuttVars in init.h +" CHECKED 2020-06-21 +" List of DT_NUMBER or DT_LONG in MuttVars in mutt_config.c syntax keyword muttrcVarNum skipwhite contained - \ connect_timeout debug_level history imap_keepalive imap_pipeline_depth - \ imap_poll_timeout mail_check mail_check_stats_interval menu_context - \ net_inc nm_db_limit nm_open_timeout nm_query_window_current_position - \ nm_query_window_duration nntp_context nntp_poll pager_context - \ pager_index_lines pgp_timeout pop_checkinterval read_inc reflow_wrap - \ save_history score_threshold_delete score_threshold_flag - \ score_threshold_read search_context sendmail_wait sidebar_component_depth - \ sidebar_width skip_quoted_offset sleep_time smime_timeout - \ ssl_min_dh_prime_bits timeout time_inc wrap wrap_headers write_inc - \ header_cache_pagesize imap_fetch_chunk_size toggle_quoted_show_levels - \ nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr + \ connect_timeout debug_level header_cache_compress_level history + \ imap_fetch_chunk_size imap_keepalive imap_pipeline_depth imap_poll_timeout mail_check + \ mail_check_stats_interval menu_context net_inc nm_db_limit nm_open_timeout + \ nm_query_window_current_position nm_query_window_duration nntp_context nntp_poll + \ pager_context pager_index_lines pgp_timeout pop_checkinterval read_inc reflow_wrap + \ save_history score_threshold_delete score_threshold_flag score_threshold_read + \ search_context sendmail_wait sidebar_component_depth sidebar_width skip_quoted_offset + \ sleep_time smime_timeout ssl_min_dh_prime_bits timeout time_inc toggle_quoted_show_levels + \ wrap wrap_headers write_inc + \ nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr syntax keyword muttrcVarDeprecatedNum contained skipwhite - \ wrapmargin - \ nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr + \ header_cache_pagesize wrapmargin + \ nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr -" CHECKED 2019-11-02 -" List of DT_STRING in MuttVars in init.h +" CHECKED 2020-06-21 +" List of DT_STRING in MuttVars in mutt_config.c " Special cases first, and all the rest at the end " Formats themselves must be updated in their respective groups " See s:escapesConditionals -syntax match muttrcVarStr contained skipwhite 'my_[a-zA-Z0-9_]\+' nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax match muttrcVarStr contained skipwhite 'my_[a-zA-Z0-9_]\+' nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr syntax keyword muttrcVarStr contained skipwhite alias_format nextgroup=muttrcVarEqualsAliasFmt syntax keyword muttrcVarStr contained skipwhite attach_format nextgroup=muttrcVarEqualsAttachFmt syntax keyword muttrcVarStr contained skipwhite compose_format nextgroup=muttrcVarEqualsComposeFmt syntax keyword muttrcVarStr contained skipwhite folder_format vfolder_format nextgroup=muttrcVarEqualsFolderFmt -syntax keyword muttrcVarStr contained skipwhite attribution index_format message_format pager_format nextgroup=muttrcVarEqualsIdxFmt -" Deprecated format -syntax keyword muttrcVarDeprecatedStr contained skipwhite hdr_format msg_format nextgroup=muttrcVarEqualsIdxFmt +syntax keyword muttrcVarStr contained skipwhite attribution forward_format index_format message_format pager_format nextgroup=muttrcVarEqualsIdxFmt syntax keyword muttrcVarStr contained skipwhite mix_entry_format nextgroup=muttrcVarEqualsMixFmt syntax keyword muttrcVarStr contained skipwhite - \ pgp_clearsign_command pgp_decode_command pgp_decrypt_command - \ pgp_encrypt_only_command pgp_encrypt_sign_command pgp_export_command - \ pgp_import_command pgp_list_pubring_command pgp_list_secring_command - \ pgp_sign_command pgp_verify_command pgp_verify_key_command - \ nextgroup=muttrcVarEqualsPGPCmdFmt + \ pgp_clearsign_command pgp_decode_command pgp_decrypt_command + \ pgp_encrypt_only_command pgp_encrypt_sign_command pgp_export_command pgp_getkeys_command + \ pgp_import_command pgp_list_pubring_command pgp_list_secring_command + \ pgp_sign_command pgp_verify_command pgp_verify_key_command + \ nextgroup=muttrcVarEqualsPGPCmdFmt syntax keyword muttrcVarStr contained skipwhite pgp_entry_format nextgroup=muttrcVarEqualsPGPFmt -syntax keyword muttrcVarStr contained skipwhite pgp_getkeys_command nextgroup=muttrcVarEqualsPGPGetKeysFmt syntax keyword muttrcVarStr contained skipwhite query_format nextgroup=muttrcVarEqualsQueryFmt syntax keyword muttrcVarStr contained skipwhite - \ smime_decrypt_command smime_encrypt_command smime_get_cert_command - \ smime_get_cert_email_command smime_get_signer_cert_command - \ smime_import_cert_command smime_pk7out_command smime_sign_command - \ smime_verify_command smime_verify_opaque_command - \ nextgroup=muttrcVarEqualsSmimeFmt -syntax keyword muttrcVarStr contained skipwhite ts_icon_format ts_status_format status_format nextgroup=muttrcVarEqualsStatusFmt -" Deprecated format -syntax keyword muttrcVarDeprecatedStr contained skipwhite xterm_icon xterm_title nextgroup=muttrcVarEqualsStatusFmt + \ smime_decrypt_command smime_encrypt_command smime_get_cert_command + \ smime_get_cert_email_command smime_get_signer_cert_command + \ smime_import_cert_command smime_pk7out_command smime_sign_command + \ smime_verify_command smime_verify_opaque_command + \ nextgroup=muttrcVarEqualsSmimeFmt +syntax keyword muttrcVarStr contained skipwhite status_format ts_icon_format ts_status_format nextgroup=muttrcVarEqualsStatusFmt syntax keyword muttrcVarStr contained skipwhite date_format nextgroup=muttrcVarEqualsStrftimeFmt syntax keyword muttrcVarStr contained skipwhite group_index_format nextgroup=muttrcVarEqualsGrpIdxFmt syntax keyword muttrcVarStr contained skipwhite sidebar_format nextgroup=muttrcVarEqualsSdbFmt syntax keyword muttrcVarStr contained skipwhite - \ assumed_charset attach_charset attach_sep attribution_locale charset - \ config_charset content_type default_hook dsn_notify dsn_return - \ empty_subject escape forward_attribution_intro forward_attribution_trailer - \ forward_format hidden_tags hostname - \ imap_authenticators imap_delim_chars imap_headers imap_login imap_pass - \ imap_user indent_string mailcap_path mark_macro_prefix mh_seq_flagged - \ mh_seq_replied mh_seq_unseen newsgroups_charset - \ news_server nm_default_uri nm_exclude_tags nm_query_type - \ nm_query_window_current_search nm_query_window_timebase nm_record_tags - \ nm_unread_tag nntp_authenticators nntp_pass nntp_user pgp_default_key - \ pgp_sign_as pipe_sep pop_authenticators pop_host pop_pass pop_user - \ postpone_encrypt_as post_indent_string preconnect realname send_charset - \ show_multipart_alternative sidebar_delim_chars sidebar_divider_char - \ sidebar_indent_string simple_search smime_default_key smime_encrypt_with - \ smime_sign_as smime_sign_digest_alg smtp_authenticators smtp_pass smtp_url - \ spam_separator ssl_ciphers autocrypt_acct_format - \ crypt_protected_headers_subject header_cache_backend nm_flagged_tag - \ nm_replied_tag preferred_languages - \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr + \ abort_key arrow_string assumed_charset attach_charset attach_sep attribution_locale + \ autocrypt_acct_format charset config_charset content_type crypt_protected_headers_subject + \ default_hook dsn_notify dsn_return empty_subject escape forward_attribution_intro + \ forward_attribution_trailer header_cache_backend header_cache_compress_method hidden_tags + \ hostname imap_authenticators imap_delim_chars imap_headers imap_login imap_pass imap_user + \ indent_string mailcap_path mark_macro_prefix mh_seq_flagged mh_seq_replied mh_seq_unseen + \ newsgroups_charset news_server nm_default_url nm_exclude_tags nm_flagged_tag nm_query_type + \ nm_query_window_current_search nm_query_window_timebase nm_record_tags nm_replied_tag + \ nm_unread_tag nntp_authenticators nntp_pass nntp_user pgp_default_key pgp_sign_as pipe_sep + \ pop_authenticators pop_host pop_pass pop_user postpone_encrypt_as post_indent_string + \ preconnect preferred_languages realname send_charset show_multipart_alternative + \ sidebar_delim_chars sidebar_divider_char sidebar_indent_string simple_search + \ smime_default_key smime_encrypt_with smime_sign_as smime_sign_digest_alg + \ smtp_authenticators smtp_pass smtp_url smtp_user spam_separator ssl_ciphers + \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr + " Deprecated strings -syntax keyword muttrcVarDeprecatedStr contained skipwhite - \ forw_format indent_str pgp_self_encrypt_as post_indent_str - \ smime_self_encrypt_as - \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax keyword muttrcVarDeprecatedStr + \ abort_noattach_regexp attach_keyword forw_format hdr_format indent_str msg_format + \ nm_default_uri pgp_self_encrypt_as post_indent_str print_cmd quote_regexp reply_regexp + \ smime_self_encrypt_as xterm_icon xterm_title -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " List of DT_ADDRESS -syntax keyword muttrcVarStr contained skipwhite envelope_from_address from nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax keyword muttrcVarStr contained skipwhite envelope_from_address from nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr " List of DT_ENUM -syntax keyword muttrcVarStr contained skipwhite mbox_type nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax keyword muttrcVarStr contained skipwhite mbox_type nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr " List of DT_MBTABLE -syntax keyword muttrcVarStr contained skipwhite crypt_chars flag_chars from_chars status_chars to_chars nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax keyword muttrcVarStr contained skipwhite crypt_chars flag_chars from_chars status_chars to_chars nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " List of DT_PATH syntax keyword muttrcVarStr contained skipwhite - \ alias_file attach_save_dir autocrypt_dir certificate_file debug_file - \ entropy_file folder header_cache history_file mbox message_cachedir newsrc - \ news_cache_dir postponed record signature smime_ca_location - \ smime_certificates smime_keys spoolfile ssl_ca_certificates_file - \ ssl_client_cert tmpdir trash - \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr + \ alias_file attach_save_dir autocrypt_dir certificate_file debug_file + \ entropy_file folder header_cache history_file mbox message_cachedir newsrc + \ news_cache_dir postponed record signature smime_ca_location + \ smime_certificates smime_keys spoolfile ssl_ca_certificates_file + \ ssl_client_cert tmpdir trash + \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr " List of DT_COMMAND (excluding pgp_*_command and smime_*_command) syntax keyword muttrcVarStr contained skipwhite - \ display_filter editor inews ispell mixmaster new_mail_command pager - \ print_command query_command sendmail shell visual external_search_command - \ imap_oauth_refresh_command pop_oauth_refresh_command - \ mime_type_query_command smtp_oauth_refresh_command tunnel - \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr + \ display_filter editor inews ispell mixmaster new_mail_command pager + \ print_command query_command sendmail shell visual external_search_command + \ imap_oauth_refresh_command pop_oauth_refresh_command + \ mime_type_query_command smtp_oauth_refresh_command tunnel + \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr -" CHECKED 2019-11-02 +" CHECKED 2020-06-21 " List of DT_REGEX syntax keyword muttrcVarStr contained skipwhite - \ abort_noattach_regex gecos_mask mask pgp_decryption_okay pgp_good_sign - \ quote_regex reply_regex smileys - \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -" List of deprecated DT_STRING|DT_COMMAND -syntax keyword muttrcVarDeprecatedStr contained skipwhite print_cmd nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr -" List of deprecated DT_REGEX -syntax keyword muttrcVarDeprecatedStr contained skipwhite abort_noattach_regexp attach_keyword quote_regexp reply_regexp nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr + \ abort_noattach_regex gecos_mask mask pgp_decryption_okay pgp_good_sign + \ quote_regex reply_regex smileys + \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr " List of DT_SORT syntax keyword muttrcVarStr contained skipwhite - \ pgp_sort_keys sidebar_sort_method sort sort_alias sort_aux sort_browser - \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr + \ pgp_sort_keys sidebar_sort_method sort sort_alias sort_aux sort_browser + \ nextgroup=muttrcSetStrAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr -" CHECKED 2019-11-02 -" List of commands in Commands in init.h +" CHECKED 2020-06-21 +" List of commands in Commands in mutt_config.c " Remember to remove hooks, they have already been dealt with -syntax keyword muttrcCommand skipwhite charset-hook nextgroup=muttrcRXString -syntax keyword muttrcCommand skipwhite unhook nextgroup=muttrcHooks -syntax keyword muttrcCommand skipwhite spam nextgroup=muttrcSpamPattern -syntax keyword muttrcCommand skipwhite nospam nextgroup=muttrcNoSpamPattern -syntax keyword muttrcCommand skipwhite bind nextgroup=muttrcBindMenuList,muttrcBindMenuListNL -syntax keyword muttrcCommand skipwhite macro nextgroup=muttrcMacroMenuList,muttrcMacroMenuListNL syntax keyword muttrcCommand skipwhite alias nextgroup=muttrcAliasGroupDef,muttrcAliasKey,muttrcAliasNL -syntax keyword muttrcCommand skipwhite unalias nextgroup=muttrcUnAliasKey,muttrcUnAliasNL -syntax keyword muttrcCommand skipwhite set unset reset toggle nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr,muttrcVarDeprecatedBool,muttrcVarDeprecatedQuad,muttrcVarDeprecatedStr +syntax keyword muttrcCommand skipwhite bind nextgroup=muttrcBindMenuList,muttrcBindMenuListNL syntax keyword muttrcCommand skipwhite exec nextgroup=muttrcFunction +syntax keyword muttrcCommand skipwhite macro nextgroup=muttrcMacroMenuList,muttrcMacroMenuListNL +syntax keyword muttrcCommand skipwhite nospam nextgroup=muttrcNoSpamPattern +syntax keyword muttrcCommand skipwhite set unset reset toggle nextgroup=muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr +syntax keyword muttrcCommand skipwhite spam nextgroup=muttrcSpamPattern +syntax keyword muttrcCommand skipwhite unalias nextgroup=muttrcUnAliasKey,muttrcUnAliasNL +syntax keyword muttrcCommand skipwhite unhook nextgroup=muttrcHooks syntax keyword muttrcCommand skipwhite - \ alternative_order attachments auto_view finish hdr_order ifdef ifndef - \ ignore lua lua-source mailboxes mailto_allow mime_lookup my_hdr push score - \ setenv sidebar_whitelist source subjectrx subscribe-to tag-formats - \ tag-transforms unalternative_order unattachments unauto_view uncolor - \ unhdr_order unignore unmailboxes unmailto_allow unmime_lookup unmono - \ unmy_hdr unscore unsetenv unsidebar_whitelist unsubjectrx unsubscribe-from - \ unvirtual-mailboxes virtual-mailboxes named-mailboxes - \ echo unbind unmacro + \ alternative_order attachments auto_view finish hdr_order ifdef ifndef + \ ignore lua lua-source mailboxes mailto_allow mime_lookup my_hdr push score + \ setenv sidebar_whitelist source subjectrx subscribe-to tag-formats + \ tag-transforms unalternative_order unattachments unauto_view uncolor + \ unhdr_order unignore unmailboxes unmailto_allow unmime_lookup unmono + \ unmy_hdr unscore unsetenv unsidebar_whitelist unsubjectrx unsubscribe-from + \ unvirtual-mailboxes virtual-mailboxes named-mailboxes + \ echo unbind unmacro -" CHECKED 2019-11-02 -" List of functions in functions.h -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" -syntax match muttrcFunction contained "\" +function! s:genFunctions(functions) + for f in a:functions + exec 'syntax match muttrcFunction contained "\<' . l:f . '\>"' + endfor +endfunction + +" CHECKED 2020-06-21 +" List of functions in functions.c +" Note: 'noop' is included but is elsewhere in the source +call s:genFunctions(['noop', + \ 'accept', 'append', 'attach-file', 'attach-key', 'attach-message', 'attach-news-message', + \ 'autocrypt-acct-menu', 'autocrypt-menu', 'backspace', 'backward-char', 'backward-word', + \ 'bol', 'bottom-page', 'bottom', 'bounce-message', 'break-thread', 'buffy-cycle', + \ 'buffy-list', 'capitalize-word', 'catchup', 'chain-next', 'chain-prev', 'change-dir', + \ 'change-folder-readonly', 'change-folder', 'change-newsgroup-readonly', + \ 'change-newsgroup', 'change-vfolder', 'check-new', 'check-stats', + \ 'check-traditional-pgp', 'clear-flag', 'collapse-all', 'collapse-parts', + \ 'collapse-thread', 'complete-query', 'complete', 'compose-to-sender', 'copy-file', + \ 'copy-message', 'create-account', 'create-alias', 'create-mailbox', 'current-bottom', + \ 'current-middle', 'current-top', 'decode-copy', 'decode-save', 'decrypt-copy', + \ 'decrypt-save', 'delete-account', 'delete-char', 'delete-entry', 'delete-mailbox', + \ 'delete-message', 'delete-pattern', 'delete-subthread', 'delete-thread', 'delete', + \ 'descend-directory', 'detach-file', 'display-address', 'display-filename', + \ 'display-message', 'display-toggle-weed', 'downcase-word', 'edit-bcc', 'edit-cc', + \ 'edit-description', 'edit-encoding', 'edit-fcc', 'edit-file', 'edit-followup-to', + \ 'edit-from', 'edit-headers', 'edit-label', 'edit-language', 'edit-message', 'edit-mime', + \ 'edit-newsgroups', 'edit-or-view-raw-message', 'edit-raw-message', 'edit-reply-to', + \ 'edit-subject', 'edit-to', 'edit-type', 'edit-x-comment-to', 'edit', 'end-cond', + \ 'enter-command', 'enter-mask', 'entire-thread', 'eol', 'exit', 'extract-keys', + \ 'fetch-mail', 'filter-entry', 'first-entry', 'flag-message', 'followup-message', + \ 'forget-passphrase', 'forward-char', 'forward-message', 'forward-to-group', + \ 'forward-word', 'get-attachment', 'get-children', 'get-message', 'get-parent', + \ 'goto-folder', 'goto-parent', 'group-alternatives', 'group-chat-reply', + \ 'group-multilingual', 'group-reply', 'half-down', 'half-up', 'help', 'history-down', + \ 'history-search', 'history-up', 'imap-fetch-mail', 'imap-logout-all', 'insert', 'ispell', + \ 'jump', 'kill-eol', 'kill-eow', 'kill-line', 'kill-word', 'last-entry', + \ 'limit-current-thread', 'limit', 'link-threads', 'list-reply', 'mail-key', + \ 'mailbox-cycle', 'mailbox-list', 'mail', 'mark-as-new', 'mark-message', 'middle-page', + \ 'mix', 'modify-labels-then-hide', 'modify-labels', 'modify-tags-then-hide', + \ 'modify-tags', 'move-down', 'move-up', 'new-mime', 'next-entry', 'next-line', + \ 'next-new-then-unread', 'next-new', 'next-page', 'next-subthread', 'next-thread', + \ 'next-undeleted', 'next-unread-mailbox', 'next-unread', 'parent-message', 'pgp-menu', + \ 'pipe-entry', 'pipe-message', 'post-message', 'postpone-message', 'previous-entry', + \ 'previous-line', 'previous-new-then-unread', 'previous-new', 'previous-page', + \ 'previous-subthread', 'previous-thread', 'previous-undeleted', 'previous-unread', + \ 'print-entry', 'print-message', 'purge-message', 'purge-thread', 'quasi-delete', + \ 'query-append', 'query', 'quit', 'quote-char', 'read-subthread', 'read-thread', + \ 'recall-message', 'reconstruct-thread', 'redraw-screen', 'refresh', 'reload-active', + \ 'rename-attachment', 'rename-file', 'rename-mailbox', 'reply', 'resend-message', + \ 'root-message', 'save-entry', 'save-message', 'search-next', 'search-opposite', + \ 'search-reverse', 'search-toggle', 'search', 'select-entry', 'select-new', + \ 'send-message', 'set-flag', 'shell-escape', 'show-limit', 'show-log-messages', + \ 'show-version', 'sidebar-next-new', 'sidebar-first', 'sidebar-last', 'sidebar-next', + \ 'sidebar-open', 'sidebar-page-down', 'sidebar-page-up', 'sidebar-prev-new', + \ 'sidebar-prev', 'sidebar-toggle-virtual', 'sidebar-toggle-visible', 'skip-quoted', + \ 'smime-menu', 'sort-mailbox', 'sort-reverse', 'sort', 'subscribe-pattern', + \ 'sync-mailbox', 'tag-entry', 'tag-message', 'tag-pattern', 'tag-prefix-cond', + \ 'tag-prefix', 'tag-subthread', 'tag-thread', 'toggle-active', 'toggle-disposition', + \ 'toggle-mailboxes', 'toggle-new', 'toggle-prefer-encrypt', 'toggle-quoted', + \ 'toggle-read', 'toggle-recode', 'toggle-subscribed', 'toggle-unlink', 'toggle-write', + \ 'top-page', 'top', 'transpose-chars', 'uncatchup', 'undelete-entry', 'undelete-message', + \ 'undelete-pattern', 'undelete-subthread', 'undelete-thread', 'unsubscribe-pattern', + \ 'untag-pattern', 'upcase-word', 'update-encoding', 'verify-key', + \ 'vfolder-from-query-readonly', 'vfolder-from-query', 'vfolder-window-backward', + \ 'vfolder-window-forward', 'view-attachments', 'view-attach', 'view-file', 'view-mailcap', + \ 'view-name', 'view-raw-message', 'view-text', 'what-key', 'write-fcc' + \ ]) " Define the default highlighting. " Only when an item doesn't have highlighting yet -highlight def link muttrcComment Comment -highlight def link muttrcEscape SpecialChar -highlight def link muttrcRXChars SpecialChar -highlight def link muttrcString String -highlight def link muttrcRXString String -highlight def link muttrcRXString2 String -highlight def link muttrcSpecial Special -highlight def link muttrcHooks Type -highlight def link muttrcGroupFlag Type -highlight def link muttrcGroupDef Macro -highlight def link muttrcAddrDef muttrcGroupFlag -highlight def link muttrcRXDef muttrcGroupFlag -highlight def link muttrcRXPat String -highlight def link muttrcAliasGroupName Macro -highlight def link muttrcAliasKey Identifier -highlight def link muttrcUnAliasKey Identifier -highlight def link muttrcAliasEncEmail Identifier -highlight def link muttrcAliasParens Type -highlight def link muttrcSetNumAssignment Number highlight def link muttrcSetBoolAssignment Boolean highlight def link muttrcSetQuadAssignment Boolean -highlight def link muttrcSetStrAssignment String -highlight def link muttrcEmail Special -highlight def link muttrcVariableInner Special -highlight def link muttrcEscapedVariable String -highlight def link muttrcHeader Type -highlight def link muttrcKeySpecial SpecialChar -highlight def link muttrcKey Type -highlight def link muttrcKeyName SpecialChar -highlight def link muttrcVarBool Identifier -highlight def link muttrcVarQuad Identifier -highlight def link muttrcVarNum Identifier -highlight def link muttrcVarStr Identifier -highlight def link muttrcMenu Identifier -highlight def link muttrcCommand Keyword -highlight def link muttrcMacroDescr String -highlight def link muttrcAction Macro + +highlight def link muttrcComment Comment + +highlight def link muttrcAlternatesLine Error highlight def link muttrcBadAction Error highlight def link muttrcBindFunction Error highlight def link muttrcBindMenuList Error -highlight def link muttrcFunction Macro -highlight def link muttrcGroupKeyword muttrcCommand -highlight def link muttrcGroupLine Error -highlight def link muttrcSubscribeKeyword muttrcCommand -highlight def link muttrcSubscribeLine Error -highlight def link muttrcListsKeyword muttrcCommand -highlight def link muttrcListsLine Error -highlight def link muttrcAlternateKeyword muttrcCommand -highlight def link muttrcAlternatesLine Error -highlight def link muttrcAttachmentsLine muttrcCommand -highlight def link muttrcAttachmentsFlag Type -highlight def link muttrcAttachmentsMimeType String -highlight def link muttrcColorLine Error -highlight def link muttrcColorContext Error -highlight def link muttrcColorContextI Identifier -highlight def link muttrcColorContextH Identifier -highlight def link muttrcColorKeyword muttrcCommand -highlight def link muttrcColorField Identifier -highlight def link muttrcColorCompose Identifier -highlight def link muttrcColorComposeField Identifier -highlight def link muttrcColor Type -highlight def link muttrcColorFG Error -highlight def link muttrcColorFGI Error -highlight def link muttrcColorFGH Error highlight def link muttrcColorBG Error -highlight def link muttrcColorBGI Error highlight def link muttrcColorBGH Error -highlight def link muttrcMonoAttrib muttrcColor -highlight def link muttrcMono muttrcCommand -highlight def link muttrcSimplePat Identifier -highlight def link muttrcSimplePatString Macro -highlight def link muttrcSimplePatMetas Special -highlight def link muttrcPattern Error -highlight def link muttrcUnColorLine Error -highlight def link muttrcUnColorKeyword muttrcCommand -highlight def link muttrcUnColorIndex Identifier -highlight def link muttrcShellString muttrcEscape -highlight def link muttrcRXHooks muttrcCommand -highlight def link muttrcRXHookNot Type -highlight def link muttrcPatHooks muttrcCommand -highlight def link muttrcPatHookNot Type -highlight def link muttrcFormatConditionals2 Type -highlight def link muttrcIndexFormatStr muttrcString -highlight def link muttrcIndexFormatEscapes muttrcEscape -highlight def link muttrcIndexFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcAliasFormatStr muttrcString -highlight def link muttrcAliasFormatEscapes muttrcEscape -highlight def link muttrcAttachFormatStr muttrcString -highlight def link muttrcAttachFormatEscapes muttrcEscape -highlight def link muttrcAttachFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcComposeFormatStr muttrcString -highlight def link muttrcComposeFormatEscapes muttrcEscape -highlight def link muttrcFolderFormatStr muttrcString -highlight def link muttrcFolderFormatEscapes muttrcEscape -highlight def link muttrcFolderFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcMixFormatStr muttrcString -highlight def link muttrcMixFormatEscapes muttrcEscape -highlight def link muttrcMixFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcPGPFormatStr muttrcString -highlight def link muttrcPGPFormatEscapes muttrcEscape -highlight def link muttrcPGPFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcPGPCmdFormatStr muttrcString -highlight def link muttrcPGPCmdFormatEscapes muttrcEscape -highlight def link muttrcPGPCmdFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcStatusFormatStr muttrcString -highlight def link muttrcStatusFormatEscapes muttrcEscape -highlight def link muttrcStatusFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcPGPGetKeysFormatStr muttrcString -highlight def link muttrcPGPGetKeysFormatEscapes muttrcEscape -highlight def link muttrcSmimeFormatStr muttrcString -highlight def link muttrcSmimeFormatEscapes muttrcEscape -highlight def link muttrcSmimeFormatConditionals muttrcFormatConditionals2 -highlight def link muttrcTimeEscapes muttrcEscape -highlight def link muttrcPGPTimeEscapes muttrcEscape -highlight def link muttrcStrftimeEscapes Type -highlight def link muttrcStrftimeFormatStr muttrcString +highlight def link muttrcColorBGI Error +highlight def link muttrcColorContext Error +highlight def link muttrcColorFG Error +highlight def link muttrcColorFGH Error +highlight def link muttrcColorFGI Error +highlight def link muttrcColorLine Error highlight def link muttrcFormatErrors Error - -highlight def link muttrcBindFunctionNL SpecialChar -highlight def link muttrcBindKeyNL SpecialChar -highlight def link muttrcBindMenuListNL SpecialChar -highlight def link muttrcMacroDescrNL SpecialChar -highlight def link muttrcMacroBodyNL SpecialChar -highlight def link muttrcMacroKeyNL SpecialChar -highlight def link muttrcMacroMenuListNL SpecialChar -highlight def link muttrcColorMatchCountNL SpecialChar -highlight def link muttrcColorNL SpecialChar -highlight def link muttrcColorRXNL SpecialChar -highlight def link muttrcColorBGNL SpecialChar -highlight def link muttrcColorFGNL SpecialChar -highlight def link muttrcAliasNameNL SpecialChar -highlight def link muttrcAliasENNL SpecialChar -highlight def link muttrcAliasNL SpecialChar -highlight def link muttrcUnAliasNL SpecialChar -highlight def link muttrcAliasGroupDefNL SpecialChar -highlight def link muttrcAliasEncEmailNL SpecialChar -highlight def link muttrcPatternNL SpecialChar -highlight def link muttrcUnColorPatNL SpecialChar -highlight def link muttrcUnColorAPNL SpecialChar -highlight def link muttrcUnColorIndexNL SpecialChar -highlight def link muttrcStringNL SpecialChar - +highlight def link muttrcGroupLine Error +highlight def link muttrcListsLine Error +highlight def link muttrcPattern Error +highlight def link muttrcSubscribeLine Error +highlight def link muttrcUnColorLine Error highlight def link muttrcVarDeprecatedBool Error highlight def link muttrcVarDeprecatedQuad Error highlight def link muttrcVarDeprecatedStr Error +highlight def link muttrcAliasEncEmail Identifier +highlight def link muttrcAliasKey Identifier +highlight def link muttrcColorCompose Identifier +highlight def link muttrcColorComposeField Identifier +highlight def link muttrcColorContextH Identifier +highlight def link muttrcColorContextI Identifier +highlight def link muttrcColorField Identifier +highlight def link muttrcMenu Identifier +highlight def link muttrcSimplePat Identifier +highlight def link muttrcUnAliasKey Identifier +highlight def link muttrcUnColorIndex Identifier +highlight def link muttrcVarBool Identifier +highlight def link muttrcVarNum Identifier +highlight def link muttrcVarQuad Identifier +highlight def link muttrcVarStr Identifier + +highlight def link muttrcCommand Keyword + +highlight def link muttrcAction Macro +highlight def link muttrcAliasGroupName Macro +highlight def link muttrcFunction Macro +highlight def link muttrcGroupDef Macro +highlight def link muttrcSimplePatString Macro + +highlight def link muttrcMonoAttrib muttrcColor + +highlight def link muttrcAlternateKeyword muttrcCommand +highlight def link muttrcAttachmentsLine muttrcCommand +highlight def link muttrcColorKeyword muttrcCommand +highlight def link muttrcGroupKeyword muttrcCommand +highlight def link muttrcListsKeyword muttrcCommand +highlight def link muttrcMono muttrcCommand +highlight def link muttrcPatHooks muttrcCommand +highlight def link muttrcRXHooks muttrcCommand +highlight def link muttrcSubscribeKeyword muttrcCommand +highlight def link muttrcUnColorKeyword muttrcCommand + +highlight def link muttrcAliasFormatEscapes muttrcEscape +highlight def link muttrcAttachFormatEscapes muttrcEscape +highlight def link muttrcComposeFormatEscapes muttrcEscape +highlight def link muttrcFolderFormatEscapes muttrcEscape +highlight def link muttrcGroupIndexFormatEscapes muttrcEscape +highlight def link muttrcIndexFormatEscapes muttrcEscape +highlight def link muttrcMixFormatEscapes muttrcEscape +highlight def link muttrcPGPCmdFormatEscapes muttrcEscape +highlight def link muttrcPGPFormatEscapes muttrcEscape +highlight def link muttrcPGPTimeEscapes muttrcEscape +highlight def link muttrcQueryFormatEscapes muttrcEscape +highlight def link muttrcShellString muttrcEscape +highlight def link muttrcSidebarFormatEscapes muttrcEscape +highlight def link muttrcSmimeFormatEscapes muttrcEscape +highlight def link muttrcStatusFormatEscapes muttrcEscape +highlight def link muttrcTimeEscapes muttrcEscape + +highlight def link muttrcAliasFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcAttachFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcComposeFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcFolderFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcIndexFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcMixFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcPGPCmdFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcPGPFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcSmimeFormatConditionals muttrcFormatConditionals2 +highlight def link muttrcStatusFormatConditionals muttrcFormatConditionals2 + +highlight def link muttrcAddrDef muttrcGroupFlag +highlight def link muttrcRXDef muttrcGroupFlag + +highlight def link muttrcAliasFormatStr muttrcString +highlight def link muttrcAttachFormatStr muttrcString +highlight def link muttrcComposeFormatStr muttrcString +highlight def link muttrcFolderFormatStr muttrcString +highlight def link muttrcGroupIndexFormatStr muttrcString +highlight def link muttrcIndexFormatStr muttrcString +highlight def link muttrcMixFormatStr muttrcString +highlight def link muttrcPGPCmdFormatStr muttrcString +highlight def link muttrcPGPFormatStr muttrcString +highlight def link muttrcQueryFormatStr muttrcString +highlight def link muttrcSidebarFormatStr muttrcString +highlight def link muttrcSmimeFormatStr muttrcString +highlight def link muttrcStatusFormatStr muttrcString +highlight def link muttrcStrftimeFormatStr muttrcString + +highlight def link muttrcSetNumAssignment Number + +highlight def link muttrcEmail Special +highlight def link muttrcSimplePatMetas Special +highlight def link muttrcSpecial Special +highlight def link muttrcVariableInner Special + +highlight def link muttrcAliasEncEmailNL SpecialChar +highlight def link muttrcAliasENNL SpecialChar +highlight def link muttrcAliasGroupDefNL SpecialChar +highlight def link muttrcAliasNameNL SpecialChar +highlight def link muttrcAliasNL SpecialChar +highlight def link muttrcBindFunctionNL SpecialChar +highlight def link muttrcBindKeyNL SpecialChar +highlight def link muttrcBindMenuListNL SpecialChar +highlight def link muttrcColorBGNL SpecialChar +highlight def link muttrcColorFGNL SpecialChar +highlight def link muttrcColorMatchCountNL SpecialChar +highlight def link muttrcColorNL SpecialChar +highlight def link muttrcColorRXNL SpecialChar +highlight def link muttrcEscape SpecialChar +highlight def link muttrcKeyName SpecialChar +highlight def link muttrcKeySpecial SpecialChar +highlight def link muttrcMacroBodyNL SpecialChar +highlight def link muttrcMacroDescrNL SpecialChar +highlight def link muttrcMacroKeyNL SpecialChar +highlight def link muttrcMacroMenuListNL SpecialChar +highlight def link muttrcPatternNL SpecialChar +highlight def link muttrcRXChars SpecialChar +highlight def link muttrcStringNL SpecialChar +highlight def link muttrcUnAliasNL SpecialChar +highlight def link muttrcUnColorAPNL SpecialChar +highlight def link muttrcUnColorIndexNL SpecialChar +highlight def link muttrcUnColorPatNL SpecialChar + +highlight def link muttrcAttachmentsMimeType String +highlight def link muttrcEscapedVariable String +highlight def link muttrcMacroDescr String +highlight def link muttrcRXPat String +highlight def link muttrcRXString String +highlight def link muttrcRXString2 String +highlight def link muttrcSetStrAssignment String +highlight def link muttrcString String + +highlight def link muttrcAliasParens Type +highlight def link muttrcAttachmentsFlag Type +highlight def link muttrcColor Type +highlight def link muttrcFormatConditionals2 Type +highlight def link muttrcGroupFlag Type +highlight def link muttrcHeader Type +highlight def link muttrcHooks Type +highlight def link muttrcKey Type +highlight def link muttrcPatHookNot Type +highlight def link muttrcRXHookNot Type +highlight def link muttrcStrftimeEscapes Type + let b:current_syntax = "neomuttrc" let &cpo = s:cpo_save diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 890c9568e0..157dc94956 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -753,6 +753,7 @@ OBJ = \ $(OUTDIR)/main.o \ $(OUTDIR)/map.o \ $(OUTDIR)/mark.o \ + $(OUTDIR)/match.o \ $(OUTDIR)/memfile.o \ $(OUTDIR)/memline.o \ $(OUTDIR)/menu.o \ diff --git a/src/Make_morph.mak b/src/Make_morph.mak index ce615b2e37..bd95115a39 100644 --- a/src/Make_morph.mak +++ b/src/Make_morph.mak @@ -72,6 +72,7 @@ SRC = arabic.c \ main.c \ map.c \ mark.c \ + match.c \ mbyte.c \ memfile.c \ memline.c \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index 3239974c9f..b1bb8836e0 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -775,6 +775,7 @@ OBJ = \ $(OUTDIR)\main.obj \ $(OUTDIR)\map.obj \ $(OUTDIR)\mark.obj \ + $(OUTDIR)\match.obj \ $(OUTDIR)\mbyte.obj \ $(OUTDIR)\memfile.obj \ $(OUTDIR)\memline.obj \ @@ -1671,6 +1672,8 @@ $(OUTDIR)/map.obj: $(OUTDIR) map.c $(INCL) $(OUTDIR)/mark.obj: $(OUTDIR) mark.c $(INCL) +$(OUTDIR)/match.obj: $(OUTDIR) match.c $(INCL) + $(OUTDIR)/memfile.obj: $(OUTDIR) memfile.c $(INCL) $(OUTDIR)/memline.obj: $(OUTDIR) memline.c $(INCL) @@ -1935,6 +1938,7 @@ proto.h: \ proto/main.pro \ proto/map.pro \ proto/mark.pro \ + proto/match.pro \ proto/memfile.pro \ proto/memline.pro \ proto/menu.pro \ diff --git a/src/Make_vms.mms b/src/Make_vms.mms index 1194acdd43..78f9dab5db 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -347,6 +347,7 @@ SRC = \ main.c \ map.c \ mark.c \ + match.c \ mbyte.c \ memfile.c \ memline.c \ @@ -460,6 +461,7 @@ OBJ = \ main.obj \ map.obj \ mark.obj \ + match.obj \ mbyte.obj \ memfile.obj \ memline.obj \ @@ -867,6 +869,9 @@ map.obj : map.c vim.h [.auto]config.h feature.h os_unix.h \ mark.obj : mark.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 +match.obj : match.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 memfile.obj : memfile.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 98cc2b3f65..c58acb9ded 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1666,6 +1666,7 @@ BASIC_SRC = \ main.c \ map.c \ mark.c \ + match.c \ mbyte.c \ memfile.c \ memline.c \ @@ -1814,6 +1815,7 @@ OBJ_COMMON = \ objects/list.o \ objects/map.o \ objects/mark.o \ + objects/match.o \ objects/mbyte.o \ objects/memline.o \ objects/menu.o \ @@ -1988,6 +1990,7 @@ PRO_AUTO = \ main.pro \ map.pro \ mark.pro \ + match.pro \ mbyte.pro \ memfile.pro \ memline.pro \ @@ -2322,7 +2325,6 @@ test1 \ test42 test44 test49 \ test52 test59 \ test70 \ - test86 test87 \ test99: cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) @@ -3405,6 +3407,9 @@ objects/map.o: map.c objects/mark.o: mark.c $(CCC) -o $@ mark.c +objects/match.o: match.c + $(CCC) -o $@ match.c + objects/memfile.o: memfile.c $(CCC) -o $@ memfile.c @@ -4034,6 +4039,10 @@ objects/mark.o: mark.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/match.o: match.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/mbyte.o: mbyte.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 6cc0704727..a196f2b954 100644 --- a/src/README.md +++ b/src/README.md @@ -51,8 +51,9 @@ getchar.c | getting characters and key mapping highlight.c | syntax highlighting indent.c | text indentation insexpand.c | Insert mode completion -mark.c | marks map.c | mapping and abbreviations +mark.c | marks +match.c | highlight matching mbyte.c | multi-byte character handling memfile.c | storing lines for buffers in a swapfile memline.c | storing lines for buffers in memory diff --git a/src/auto/configure b/src/auto/configure index 4ae5065326..9fc0e269f1 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -14276,8 +14276,8 @@ else main() { uint32_t nr1 = (uint32_t)-1; uint32_t nr2 = (uint32_t)0xffffffffUL; - if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) exit(1); - exit(0); + if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) return 1; + return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : diff --git a/src/beval.c b/src/beval.c index b7d9226e70..dd7bc3cdc7 100644 --- a/src/beval.c +++ b/src/beval.c @@ -285,7 +285,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) ++textwinlock; vim_free(result); - result = eval_to_string(bexpr, NULL, TRUE); + result = eval_to_string(bexpr, TRUE); // Remove one trailing newline, it is added when the result was a // list and it's hardly ever useful. If the user really wants a diff --git a/src/buffer.c b/src/buffer.c index e1ef3ecaf2..74ae39688c 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -4104,7 +4104,7 @@ build_stl_str_hl( tv.vval.v_number = wp->w_id; set_var((char_u *)"g:statusline_winid", &tv, FALSE); - usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); + usefmt = eval_to_string_safe(fmt + 2, use_sandbox); if (usefmt == NULL) usefmt = fmt; @@ -4444,7 +4444,7 @@ build_stl_str_hl( if (curwin != save_curwin) VIsual_active = FALSE; - str = eval_to_string_safe(p, &t, use_sandbox); + str = eval_to_string_safe(p, use_sandbox); curwin = save_curwin; curbuf = save_curbuf; diff --git a/src/clientserver.c b/src/clientserver.c index 33e14bb876..67a3cc36e4 100644 --- a/src/clientserver.c +++ b/src/clientserver.c @@ -86,7 +86,7 @@ eval_client_expr_to_string(char_u *expr) // to be typed. Do generate errors so that try/catch works. ++emsg_silent; - res = eval_to_string(expr, NULL, TRUE); + res = eval_to_string(expr, TRUE); debug_break_level = save_dbl; redir_off = save_ro; diff --git a/src/cmdexpand.c b/src/cmdexpand.c index c9756ec186..5c19b8c53f 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -1099,6 +1099,15 @@ set_one_cmd_context( arg = skipwhite(p); + // Skip over ++argopt argument + if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0) + { + p = arg; + while (*p && !vim_isspace(*p)) + MB_PTR_ADV(p); + arg = skipwhite(p); + } + if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) { if (*arg == '>') // append @@ -1146,14 +1155,6 @@ set_one_cmd_context( arg = skipwhite(arg); } - // Skip over ++argopt argument - if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0) - { - p = arg; - while (*p && !vim_isspace(*p)) - MB_PTR_ADV(p); - arg = skipwhite(p); - } // Check for '|' to separate commands and '"' to start comments. // Don't do this for ":read !cmd" and ":write !cmd". diff --git a/src/configure.ac b/src/configure.ac index a1eb643a15..249e95fa49 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -4249,8 +4249,8 @@ AC_TRY_RUN([ main() { uint32_t nr1 = (uint32_t)-1; uint32_t nr2 = (uint32_t)0xffffffffUL; - if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) exit(1); - exit(0); + if (sizeof(uint32_t) != 4 || nr1 != 0xffffffffUL || nr2 + 1 != 0) return 1; + return 0; }], AC_MSG_RESULT(ok), AC_MSG_ERROR([WRONG! uint32_t not defined correctly.]), diff --git a/src/dict.c b/src/dict.c index 9d94261986..a549ed71b1 100644 --- a/src/dict.c +++ b/src/dict.c @@ -787,13 +787,15 @@ get_literal_key(char_u **arg, typval_T *tv) /* * Allocate a variable for a Dictionary and fill it from "*arg". + * "*arg" points to the "{". * "literal" is TRUE for #{key: val} * Return OK or FAIL. Returns NOTDONE for {expr}. */ int -eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) +eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal) { - int evaluate = flags & EVAL_EVALUATE; + int evaluate = evalarg == NULL ? FALSE + : evalarg->eval_flags & EVAL_EVALUATE; dict_T *d = NULL; typval_T tvkey; typval_T tv; @@ -802,6 +804,7 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) char_u *start = skipwhite(*arg + 1); char_u buf[NUMBUFLEN]; int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; + int had_comma; /* * First check if it's not a curly-braces thing: {expr}. @@ -812,7 +815,7 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) */ if (!vim9script && *start != '}') { - if (eval1(&start, &tv, 0) == FAIL) // recursive! + if (eval1(&start, &tv, NULL) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; @@ -827,12 +830,12 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) tvkey.v_type = VAR_UNKNOWN; tv.v_type = VAR_UNKNOWN; - *arg = skipwhite(*arg + 1); + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); while (**arg != '}' && **arg != NUL) { if ((literal ? get_literal_key(arg, &tvkey) - : eval1(arg, &tvkey, flags)) == FAIL) // recursive! + : eval1(arg, &tvkey, evalarg)) == FAIL) // recursive! goto failret; if (**arg != ':') @@ -852,9 +855,15 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) goto failret; } } + if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1])) + { + semsg(_(e_white_after), ":"); + clear_tv(&tvkey); + goto failret; + } - *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, flags) == FAIL) // recursive! + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + if (eval1(arg, &tv, evalarg) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); @@ -882,15 +891,28 @@ eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) } clear_tv(&tvkey); + // the comma must come after the value + had_comma = **arg == ','; + if (had_comma) + { + if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1])) + { + semsg(_(e_white_after), ","); + goto failret; + } + *arg = skipwhite(*arg + 1); + } + + // the "}" can be on the next line + *arg = skipwhite_and_linebreak(*arg, evalarg); if (**arg == '}') break; - if (**arg != ',') + if (!had_comma) { if (evaluate) semsg(_(e_missing_dict_comma), *arg); goto failret; } - *arg = skipwhite(*arg + 1); } if (**arg != '}') diff --git a/src/drawline.c b/src/drawline.c index ec212fcb26..2c89f643d9 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -967,7 +967,7 @@ win_line( for (;;) { #if defined(FEAT_CONCEAL) || defined(FEAT_SEARCH_EXTRA) - int has_match_conc = 0; // match wants to conceal + int has_match_conc = 0; // match wants to conceal #endif #ifdef FEAT_CONCEAL int did_decrement_ptr = FALSE; @@ -1334,6 +1334,11 @@ win_line( &screen_search_hl, &has_match_conc, &match_conc, did_line_attr, lcs_eol_one); ptr = line + v; // "line" may have been changed + + // Do not allow a conceal over EOL otherwise EOL will be missed + // and bad things happen. + if (*ptr == NUL) + has_match_conc = 0; } #endif @@ -2353,13 +2358,14 @@ win_line( { char_attr = conceal_attr; if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1) - && (syn_get_sub_char() != NUL || match_conc - || wp->w_p_cole == 1) + && (syn_get_sub_char() != NUL + || (has_match_conc && match_conc) + || wp->w_p_cole == 1) && wp->w_p_cole != 3) { // First time at this concealed item: display one // character. - if (match_conc) + if (has_match_conc && match_conc) c = match_conc; else if (syn_get_sub_char() != NUL) c = syn_get_sub_char(); diff --git a/src/eval.c b/src/eval.c index 38afc24894..1468070ae6 100644 --- a/src/eval.c +++ b/src/eval.c @@ -38,6 +38,7 @@ typedef struct { int fi_semicolon; // TRUE if ending in '; var]' int fi_varcount; // nr of variables in the list + int fi_break_count; // nr of line breaks encountered listwatch_T fi_lw; // keep an eye on the item used. list_T *fi_list; // list being used int fi_bi; // index of blob @@ -45,13 +46,13 @@ typedef struct } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); -static int eval2(char_u **arg, typval_T *rettv, int flags); -static int eval3(char_u **arg, typval_T *rettv, int flags); -static int eval4(char_u **arg, typval_T *rettv, int flags); -static int eval5(char_u **arg, typval_T *rettv, int flags); -static int eval6(char_u **arg, typval_T *rettv, int flags, int want_string); -static int eval7(char_u **arg, typval_T *rettv, int flags, int want_string); -static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); +static int eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg); +static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); +static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); +static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); @@ -152,6 +153,18 @@ eval_clear(void) } #endif + void +fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip) +{ + CLEAR_FIELD(*evalarg); + evalarg->eval_flags = skip ? 0 : EVAL_EVALUATE; + if (eap != NULL && getline_equal(eap->getline, eap->cookie, getsourceline)) + { + evalarg->eval_getline = eap->getline; + evalarg->eval_cookie = eap->cookie; + } +} + /* * Top level evaluation function, returning a boolean. * Sets "error" to TRUE if there was an error. @@ -161,15 +174,18 @@ eval_clear(void) eval_to_bool( char_u *arg, int *error, - char_u **nextcmd, + exarg_T *eap, int skip) // only parse, don't execute { typval_T tv; varnumber_T retval = FALSE; + evalarg_T evalarg; + + fill_evalarg_from_eap(&evalarg, eap, skip); if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) + if (eval0(arg, &tv, eap, &evalarg) == FAIL) *error = TRUE; else { @@ -182,6 +198,7 @@ eval_to_bool( } if (skip) --emsg_skip; + clear_evalarg(&evalarg, eap); return (int)retval; } @@ -190,14 +207,17 @@ eval_to_bool( * Call eval1() and give an error message if not done at a lower level. */ static int -eval1_emsg(char_u **arg, typval_T *rettv, int evaluate) +eval1_emsg(char_u **arg, typval_T *rettv, exarg_T *eap) { char_u *start = *arg; int ret; int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; + evalarg_T evalarg; - ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); + fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); + + ret = eval1(arg, rettv, &evalarg); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has @@ -208,6 +228,7 @@ eval1_emsg(char_u **arg, typval_T *rettv, int evaluate) && called_emsg == called_emsg_before) semsg(_(e_invexpr2), start); } + clear_evalarg(&evalarg, eap); return ret; } @@ -277,7 +298,7 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv) if (s == NULL) return FAIL; s = skipwhite(s); - if (eval1_emsg(&s, rettv, TRUE) == FAIL) + if (eval1_emsg(&s, rettv, NULL) == FAIL) return FAIL; if (*s != NUL) // check for trailing chars after expr { @@ -317,15 +338,17 @@ eval_expr_to_bool(typval_T *expr, int *error) char_u * eval_to_string_skip( char_u *arg, - char_u **nextcmd, + exarg_T *eap, int skip) // only parse, don't execute { typval_T tv; char_u *retval; + evalarg_T evalarg; + fill_evalarg_from_eap(&evalarg, eap, skip); if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) + if (eval0(arg, &tv, eap, &evalarg) == FAIL || skip) retval = NULL; else { @@ -334,6 +357,7 @@ eval_to_string_skip( } if (skip) --emsg_skip; + clear_evalarg(&evalarg, eap); return retval; } @@ -348,7 +372,62 @@ skip_expr(char_u **pp) typval_T rettv; *pp = skipwhite(*pp); - return eval1(pp, &rettv, 0); + return eval1(pp, &rettv, NULL); +} + +/* + * Skip over an expression at "*pp". + * If in Vim9 script and line breaks are encountered, the lines are + * concatenated. "evalarg->eval_tofree" will be set accordingly. + * Return FAIL for an error, OK otherwise. + */ + int +skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg) +{ + typval_T rettv; + int res; + int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; + garray_T *gap = &evalarg->eval_ga; + int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags; + + if (vim9script && evalarg->eval_cookie != NULL) + { + ga_init2(gap, sizeof(char_u *), 10); + if (ga_grow(gap, 1) == OK) + // leave room for "start" + ++gap->ga_len; + } + + // Don't evaluate the expression. + if (evalarg != NULL) + evalarg->eval_flags &= ~EVAL_EVALUATE; + *end = skipwhite(*end); + res = eval1(end, &rettv, evalarg); + if (evalarg != NULL) + evalarg->eval_flags = save_flags; + + if (vim9script && evalarg->eval_cookie != NULL + && evalarg->eval_ga.ga_len > 1) + { + char_u *p; + size_t endoff = STRLEN(*end); + + // Line breaks encountered, concatenate all the lines. + *((char_u **)gap->ga_data) = *start; + p = ga_concat_strings(gap, ""); + *((char_u **)gap->ga_data) = NULL; + ga_clear_strings(gap); + gap->ga_itemsize = 0; + if (p == NULL) + return FAIL; + *start = p; + vim_free(evalarg->eval_tofree); + evalarg->eval_tofree = p; + // Compute "end" relative to the end. + *end = *start + STRLEN(*start) - endoff; + } + + return res; } /* @@ -360,7 +439,6 @@ skip_expr(char_u **pp) char_u * eval_to_string( char_u *arg, - char_u **nextcmd, int convert) { typval_T tv; @@ -370,7 +448,7 @@ eval_to_string( char_u numbuf[NUMBUFLEN]; #endif - if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) + if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) retval = NULL; else { @@ -397,6 +475,7 @@ eval_to_string( retval = vim_strsave(tv_get_string(&tv)); clear_tv(&tv); } + clear_evalarg(&EVALARG_EVALUATE, NULL); return retval; } @@ -408,7 +487,6 @@ eval_to_string( char_u * eval_to_string_safe( char_u *arg, - char_u **nextcmd, int use_sandbox) { char_u *retval; @@ -418,7 +496,7 @@ eval_to_string_safe( if (use_sandbox) ++sandbox; ++textwinlock; - retval = eval_to_string(arg, nextcmd, FALSE); + retval = eval_to_string(arg, FALSE); if (use_sandbox) --sandbox; --textwinlock; @@ -440,7 +518,7 @@ eval_to_number(char_u *expr) ++emsg_off; - if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) + if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) retval = -1; else { @@ -458,14 +536,18 @@ eval_to_number(char_u *expr) * Returns NULL when there is an error. */ typval_T * -eval_expr(char_u *arg, char_u **nextcmd) +eval_expr(char_u *arg, exarg_T *eap) { typval_T *tv; + evalarg_T evalarg; + + fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); tv = ALLOC_ONE(typval_T); - if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL) + if (tv != NULL && eval0(arg, tv, eap, &evalarg) == FAIL) VIM_CLEAR(tv); + clear_evalarg(&evalarg, eap); return tv; } @@ -588,7 +670,7 @@ eval_foldexpr(char_u *arg, int *cp) ++sandbox; ++textwinlock; *cp = NUL; - if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) + if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) retval = 0; else { @@ -612,6 +694,7 @@ eval_foldexpr(char_u *arg, int *cp) if (use_sandbox) --sandbox; --textwinlock; + clear_evalarg(&EVALARG_EVALUATE, NULL); return (int)retval; } @@ -666,7 +749,9 @@ get_lval( { // When skipping just find the end of the name. lp->ll_name = name; - return find_name_end(name, NULL, NULL, FNE_INCL_BR | fne_flags); + lp->ll_name_end = find_name_end(name, NULL, NULL, + FNE_INCL_BR | fne_flags); + return lp->ll_name_end; } // Find the end of the name. @@ -776,7 +861,7 @@ get_lval( else { empty1 = FALSE; - if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive! + if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { @@ -814,7 +899,7 @@ get_lval( { lp->ll_empty2 = FALSE; // recursive! - if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) + if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; @@ -1139,7 +1224,7 @@ set_var_lval( // handle +=, -=, *=, /=, %= and .= di = NULL; - if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), + if (eval_variable(lp->ll_name, (int)STRLEN(lp->ll_name), &tv, &di, TRUE, FALSE) == OK) { if ((di == NULL @@ -1417,13 +1502,14 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op) eval_for_line( char_u *arg, int *errp, - char_u **nextcmdp, - int skip) + exarg_T *eap, + evalarg_T *evalarg) { forinfo_T *fi; char_u *expr; typval_T tv; list_T *l; + int skip = !(evalarg->eval_flags & EVAL_EVALUATE); *errp = TRUE; // default: there is an error @@ -1435,8 +1521,9 @@ eval_for_line( if (expr == NULL) return fi; - expr = skipwhite(expr); - if (expr[0] != 'i' || expr[1] != 'n' || !VIM_ISWHITE(expr[2])) + expr = skipwhite_and_linebreak(expr, evalarg); + if (expr[0] != 'i' || expr[1] != 'n' + || !(expr[2] == NUL || VIM_ISWHITE(expr[2]))) { emsg(_(e_missing_in)); return fi; @@ -1444,8 +1531,8 @@ eval_for_line( if (skip) ++emsg_skip; - if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) - == OK) + expr = skipwhite_and_linebreak(expr + 2, evalarg); + if (eval0(expr, &tv, eap, evalarg) == OK) { *errp = FALSE; if (!skip) @@ -1493,10 +1580,24 @@ eval_for_line( } if (skip) --emsg_skip; + fi->fi_break_count = evalarg->eval_break_count; return fi; } +/* + * Used when looping over a :for line, skip the "in expr" part. + */ + void +skip_for_lines(void *fi_void, evalarg_T *evalarg) +{ + forinfo_T *fi = (forinfo_T *)fi_void; + int i; + + for (i = 0; i < fi->fi_break_count; ++i) + eval_next_line(evalarg); +} + /* * Use the first item in a ":for" list. Advance to the next. * Assign the values to the variable (list). "arg" points to the first one. @@ -1703,6 +1804,7 @@ pattern_match(char_u *pat, char_u *text, int ic) static int eval_func( char_u **arg, // points to "(", will be advanced + evalarg_T *evalarg, char_u *name, int name_len, typval_T *rettv, @@ -1738,7 +1840,7 @@ eval_func( funcexe.evaluate = evaluate; funcexe.partial = partial; funcexe.basetv = basetv; - ret = get_func_tv(s, len, rettv, arg, &funcexe); + ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe); } vim_free(s); @@ -1763,6 +1865,99 @@ eval_func( return ret; } +/* + * If inside Vim9 script, "arg" points to the end of a line (ignoring a # + * comment) and there is a next line, return the next line (skipping blanks) + * and set "getnext". + * Otherwise just return "arg" unmodified and set "getnext" to FALSE. + * "arg" must point somewhere inside a line, not at the start. + */ + char_u * +eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext) +{ + *getnext = FALSE; + if (current_sctx.sc_version == SCRIPT_VERSION_VIM9 + && evalarg != NULL + && evalarg->eval_cookie != NULL + && (*arg == NUL || (VIM_ISWHITE(arg[-1]) + && *arg == '#' && arg[1] != '{'))) + { + char_u *p = getline_peek(evalarg->eval_getline, evalarg->eval_cookie); + + if (p != NULL) + { + *getnext = TRUE; + return skipwhite(p); + } + } + return arg; +} + +/* + * To be called after eval_next_non_blank() sets "getnext" to TRUE. + */ + char_u * +eval_next_line(evalarg_T *evalarg) +{ + garray_T *gap = &evalarg->eval_ga; + char_u *line; + + line = evalarg->eval_getline(0, evalarg->eval_cookie, 0, TRUE); + ++evalarg->eval_break_count; + if (gap->ga_itemsize > 0 && ga_grow(gap, 1) == OK) + { + // Going to concatenate the lines after parsing. + ((char_u **)gap->ga_data)[gap->ga_len] = line; + ++gap->ga_len; + } + else + { + vim_free(evalarg->eval_tofree); + evalarg->eval_tofree = line; + } + return skipwhite(line); +} + +/* + * Call eval_next_non_blank() and get the next line if needed. + */ + char_u * +skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg) +{ + int getnext; + char_u *p = skipwhite(arg); + + if (evalarg == NULL) + return skipwhite(arg); + eval_next_non_blank(p, evalarg, &getnext); + if (getnext) + return eval_next_line(evalarg); + return p; +} + +/* + * After using "evalarg" filled from "eap" free the memory. + */ + void +clear_evalarg(evalarg_T *evalarg, exarg_T *eap) +{ + if (evalarg != NULL && evalarg->eval_tofree != NULL) + { + if (eap != NULL) + { + // We may need to keep the original command line, e.g. for + // ":let" it has the variable names. But we may also need the + // new one, "nextcmd" points into it. Keep both. + vim_free(eap->cmdline_tofree); + eap->cmdline_tofree = *eap->cmdlinep; + *eap->cmdlinep = evalarg->eval_tofree; + } + else + vim_free(evalarg->eval_tofree); + evalarg->eval_tofree = NULL; + } +} + /* * The "evaluate" argument: When FALSE, the argument is only parsed but not * executed. The function may return OK, but the rettv will be of type @@ -1774,23 +1969,25 @@ eval_func( * This calls eval1() and handles error message and nextcmd. * Put the result in "rettv" when returning OK and "evaluate" is TRUE. * Note: "rettv.v_lock" is not set. - * "flags" has EVAL_EVALUATE and similar flags. + * "evalarg" can be NULL, EVALARG_EVALUATE or a pointer. * Return OK or FAIL. */ int eval0( char_u *arg, typval_T *rettv, - char_u **nextcmd, - int flags) + exarg_T *eap, + evalarg_T *evalarg) { int ret; char_u *p; int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; + int flags = evalarg == NULL ? 0 : evalarg->eval_flags; p = skipwhite(arg); - ret = eval1(&p, rettv, flags); + ret = eval1(&p, rettv, evalarg); + if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) @@ -1808,8 +2005,9 @@ eval0( semsg(_(e_invexpr2), arg); ret = FAIL; } - if (nextcmd != NULL) - *nextcmd = check_nextcmd(p); + + if (eap != NULL) + eap->nextcmd = check_nextcmd(p); return ret; } @@ -1826,23 +2024,43 @@ eval0( * Return OK or FAIL. */ int -eval1(char_u **arg, typval_T *rettv, int flags) +eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { - int result; - typval_T var2; + char_u *p; + int getnext; /* * Get the first variable. */ - if (eval2(arg, rettv, flags) == FAIL) + if (eval2(arg, rettv, evalarg) == FAIL) return FAIL; - if ((*arg)[0] == '?') + p = eval_next_non_blank(*arg, evalarg, &getnext); + if (*p == '?') { - int evaluate = flags & EVAL_EVALUATE; + int result; + typval_T var2; + evalarg_T nested_evalarg; + int orig_flags; + int evaluate; + if (getnext) + *arg = eval_next_line(evalarg); + + if (evalarg == NULL) + { + CLEAR_FIELD(nested_evalarg); + orig_flags = 0; + } + else + { + nested_evalarg = *evalarg; + orig_flags = evalarg->eval_flags; + } + + evaluate = nested_evalarg.eval_flags & EVAL_EVALUATE; result = FALSE; - if (flags & EVAL_EVALUATE) + if (evaluate) { int error = FALSE; @@ -1856,26 +2074,33 @@ eval1(char_u **arg, typval_T *rettv, int flags) /* * Get the second variable. Recursive! */ - *arg = skipwhite(*arg + 1); - if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + nested_evalarg.eval_flags = result ? orig_flags + : orig_flags & ~EVAL_EVALUATE; + if (eval1(arg, rettv, &nested_evalarg) == FAIL) return FAIL; /* * Check for the ":". */ - if ((*arg)[0] != ':') + p = eval_next_non_blank(*arg, evalarg, &getnext); + if (*p != ':') { emsg(_(e_missing_colon)); if (evaluate && result) clear_tv(rettv); return FAIL; } + if (getnext) + *arg = eval_next_line(evalarg); /* * Get the third variable. Recursive! */ - *arg = skipwhite(*arg + 1); - if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + nested_evalarg.eval_flags = !result ? orig_flags + : orig_flags & ~EVAL_EVALUATE; + if (eval1(arg, &var2, &nested_evalarg) == FAIL) { if (evaluate && result) clear_tv(rettv); @@ -1898,8 +2123,10 @@ eval1(char_u **arg, typval_T *rettv, int flags) * Return OK or FAIL. */ static int -eval2(char_u **arg, typval_T *rettv, int flags) +eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { + char_u *p; + int getnext; typval_T var2; long result; int first; @@ -1908,7 +2135,7 @@ eval2(char_u **arg, typval_T *rettv, int flags) /* * Get the first variable. */ - if (eval3(arg, rettv, flags) == FAIL) + if (eval3(arg, rettv, evalarg) == FAIL) return FAIL; /* @@ -1916,9 +2143,28 @@ eval2(char_u **arg, typval_T *rettv, int flags) */ first = TRUE; result = FALSE; - while ((*arg)[0] == '|' && (*arg)[1] == '|') + p = eval_next_non_blank(*arg, evalarg, &getnext); + while (p[0] == '|' && p[1] == '|') { - int evaluate = flags & EVAL_EVALUATE; + evalarg_T nested_evalarg; + int evaluate; + int orig_flags; + + if (getnext) + *arg = eval_next_line(evalarg); + + if (evalarg == NULL) + { + CLEAR_FIELD(nested_evalarg); + orig_flags = 0; + evaluate = FALSE; + } + else + { + nested_evalarg = *evalarg; + orig_flags = evalarg->eval_flags; + evaluate = orig_flags & EVAL_EVALUATE; + } if (evaluate && first) { @@ -1933,9 +2179,10 @@ eval2(char_u **arg, typval_T *rettv, int flags) /* * Get the second variable. */ - *arg = skipwhite(*arg + 2); - if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) - == FAIL) + *arg = skipwhite_and_linebreak(*arg + 2, evalarg); + nested_evalarg.eval_flags = !result ? orig_flags + : orig_flags & ~EVAL_EVALUATE; + if (eval3(arg, &var2, &nested_evalarg) == FAIL) return FAIL; /* @@ -1954,6 +2201,8 @@ eval2(char_u **arg, typval_T *rettv, int flags) rettv->v_type = VAR_NUMBER; rettv->vval.v_number = result; } + + p = eval_next_non_blank(*arg, evalarg, &getnext); } return OK; @@ -1969,8 +2218,10 @@ eval2(char_u **arg, typval_T *rettv, int flags) * Return OK or FAIL. */ static int -eval3(char_u **arg, typval_T *rettv, int flags) +eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { + char_u *p; + int getnext; typval_T var2; long result; int first; @@ -1979,7 +2230,7 @@ eval3(char_u **arg, typval_T *rettv, int flags) /* * Get the first variable. */ - if (eval4(arg, rettv, flags) == FAIL) + if (eval4(arg, rettv, evalarg) == FAIL) return FAIL; /* @@ -1987,10 +2238,28 @@ eval3(char_u **arg, typval_T *rettv, int flags) */ first = TRUE; result = TRUE; - while ((*arg)[0] == '&' && (*arg)[1] == '&') + p = eval_next_non_blank(*arg, evalarg, &getnext); + while (p[0] == '&' && p[1] == '&') { - int evaluate = flags & EVAL_EVALUATE; + evalarg_T nested_evalarg; + int orig_flags; + int evaluate; + if (getnext) + *arg = eval_next_line(evalarg); + + if (evalarg == NULL) + { + CLEAR_FIELD(nested_evalarg); + orig_flags = 0; + evaluate = FALSE; + } + else + { + nested_evalarg = *evalarg; + orig_flags = evalarg->eval_flags; + evaluate = orig_flags & EVAL_EVALUATE; + } if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) @@ -2004,8 +2273,10 @@ eval3(char_u **arg, typval_T *rettv, int flags) /* * Get the second variable. */ - *arg = skipwhite(*arg + 2); - if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) + *arg = skipwhite_and_linebreak(*arg + 2, evalarg); + nested_evalarg.eval_flags = result ? orig_flags + : orig_flags & ~EVAL_EVALUATE; + if (eval4(arg, &var2, &nested_evalarg) == FAIL) return FAIL; /* @@ -2024,6 +2295,8 @@ eval3(char_u **arg, typval_T *rettv, int flags) rettv->v_type = VAR_NUMBER; rettv->vval.v_number = result; } + + p = eval_next_non_blank(*arg, evalarg, &getnext); } return OK; @@ -2048,10 +2321,11 @@ eval3(char_u **arg, typval_T *rettv, int flags) * Return OK or FAIL. */ static int -eval4(char_u **arg, typval_T *rettv, int flags) +eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { typval_T var2; char_u *p; + int getnext; int i; exptype_T type = EXPR_UNKNOWN; int len = 2; @@ -2060,10 +2334,10 @@ eval4(char_u **arg, typval_T *rettv, int flags) /* * Get the first variable. */ - if (eval5(arg, rettv, flags) == FAIL) + if (eval5(arg, rettv, evalarg) == FAIL) return FAIL; - p = *arg; + p = eval_next_non_blank(*arg, evalarg, &getnext); switch (p[0]) { case '=': if (p[1] == '=') @@ -2108,6 +2382,9 @@ eval4(char_u **arg, typval_T *rettv, int flags) */ if (type != EXPR_UNKNOWN) { + if (getnext) + *arg = eval_next_line(evalarg); + // extra question mark appended: ignore case if (p[len] == '?') { @@ -2127,13 +2404,13 @@ eval4(char_u **arg, typval_T *rettv, int flags) /* * Get the second variable. */ - *arg = skipwhite(p + len); - if (eval5(arg, &var2, flags) == FAIL) + *arg = skipwhite_and_linebreak(p + len, evalarg); + if (eval5(arg, &var2, evalarg) == FAIL) { clear_tv(rettv); return FAIL; } - if (flags & EVAL_EVALUATE) + if (evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE)) { int ret = typval_compare(rettv, &var2, type, ic); @@ -2195,23 +2472,14 @@ eval_addlist(typval_T *tv1, typval_T *tv2) * Return OK or FAIL. */ static int -eval5(char_u **arg, typval_T *rettv, int flags) +eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { - typval_T var2; - int op; - varnumber_T n1, n2; -#ifdef FEAT_FLOAT - float_T f1 = 0, f2 = 0; -#endif - char_u *s1, *s2; - char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; - char_u *p; - int concat; + int evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); /* * Get the first variable. */ - if (eval6(arg, rettv, flags, FALSE) == FAIL) + if (eval6(arg, rettv, evalarg, FALSE) == FAIL) return FAIL; /* @@ -2219,12 +2487,20 @@ eval5(char_u **arg, typval_T *rettv, int flags) */ for (;;) { + int getnext; + char_u *p; + int op; + int concat; + typval_T var2; + // "." is only string concatenation when scriptversion is 1 - op = **arg; - concat = op == '.' - && (*(*arg + 1) == '.' || current_sctx.sc_version < 2); + p = eval_next_non_blank(*arg, evalarg, &getnext); + op = *p; + concat = op == '.' && (*(p + 1) == '.' || current_sctx.sc_version < 2); if (op != '+' && op != '-' && !concat) break; + if (getnext) + *arg = eval_next_line(evalarg); if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB)) @@ -2240,7 +2516,7 @@ eval5(char_u **arg, typval_T *rettv, int flags) // we know that the first operand needs to be a string or number // without evaluating the 2nd operand. So check before to avoid // side effects after an error. - if ((flags & EVAL_EVALUATE) && tv_get_string_chk(rettv) == NULL) + if (evaluate && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; @@ -2252,22 +2528,24 @@ eval5(char_u **arg, typval_T *rettv, int flags) */ if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; - *arg = skipwhite(*arg + 1); - if (eval6(arg, &var2, flags, op == '.') == FAIL) + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + if (eval6(arg, &var2, evalarg, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } - if (flags & EVAL_EVALUATE) + if (evaluate) { /* * Compute the result. */ if (op == '.') { - s1 = tv_get_string_buf(rettv, buf1); // already checked - s2 = tv_get_string_buf_chk(&var2, buf2); + char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; + char_u *s1 = tv_get_string_buf(rettv, buf1); + char_u *s2 = tv_get_string_buf_chk(&var2, buf2); + if (s2 == NULL) // type error ? { clear_tv(rettv); @@ -2290,9 +2568,11 @@ eval5(char_u **arg, typval_T *rettv, int flags) } else { - int error = FALSE; - + int error = FALSE; + varnumber_T n1, n2; #ifdef FEAT_FLOAT + float_T f1 = 0, f2 = 0; + if (rettv->v_type == VAR_FLOAT) { f1 = rettv->vval.v_float; @@ -2381,7 +2661,7 @@ eval5(char_u **arg, typval_T *rettv, int flags) eval6( char_u **arg, typval_T *rettv, - int flags, + evalarg_T *evalarg, int want_string) // after "." operator { typval_T var2; @@ -2396,7 +2676,7 @@ eval6( /* * Get the first variable. */ - if (eval7(arg, rettv, flags, want_string) == FAIL) + if (eval7(arg, rettv, evalarg, want_string) == FAIL) return FAIL; /* @@ -2404,11 +2684,17 @@ eval6( */ for (;;) { - op = **arg; + int evaluate = evalarg == NULL ? 0 + : (evalarg->eval_flags & EVAL_EVALUATE); + int getnext; + + op = *eval_next_non_blank(*arg, evalarg, &getnext); if (op != '*' && op != '/' && op != '%') break; + if (getnext) + *arg = eval_next_line(evalarg); - if (flags & EVAL_EVALUATE) + if (evaluate) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) @@ -2431,10 +2717,10 @@ eval6( * Get the second variable. */ *arg = skipwhite(*arg + 1); - if (eval7(arg, &var2, flags, FALSE) == FAIL) + if (eval7(arg, &var2, evalarg, FALSE) == FAIL) return FAIL; - if (flags & EVAL_EVALUATE) + if (evaluate) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) @@ -2551,10 +2837,12 @@ eval6( eval7( char_u **arg, typval_T *rettv, - int flags, + evalarg_T *evalarg, int want_string) // after "." operator { - int evaluate = flags & EVAL_EVALUATE; + int flags = evalarg == NULL ? 0 : evalarg->eval_flags; + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); int len; char_u *s; char_u *start_leader, *end_leader; @@ -2601,25 +2889,30 @@ eval7( case '7': case '8': case '9': - case '.': ret = get_number_tv(arg, rettv, evaluate, want_string); + case '.': ret = eval_number(arg, rettv, evaluate, want_string); + + // Apply prefixed "-" and "+" now. Matters especially when + // "->" follows. + if (ret == OK && evaluate && end_leader > start_leader) + ret = eval7_leader(rettv, TRUE, start_leader, &end_leader); break; /* * String constant: "string". */ - case '"': ret = get_string_tv(arg, rettv, evaluate); + case '"': ret = eval_string(arg, rettv, evaluate); break; /* * Literal string constant: 'str''ing'. */ - case '\'': ret = get_lit_string_tv(arg, rettv, evaluate); + case '\'': ret = eval_lit_string(arg, rettv, evaluate); break; /* * List: [expr, expr] */ - case '[': ret = get_list_tv(arg, rettv, flags, TRUE); + case '[': ret = eval_list(arg, rettv, evalarg, TRUE); break; /* @@ -2628,7 +2921,7 @@ eval7( case '#': if ((*arg)[1] == '{') { ++*arg; - ret = eval_dict(arg, rettv, flags, TRUE); + ret = eval_dict(arg, rettv, evalarg, TRUE); } else ret = NOTDONE; @@ -2638,21 +2931,21 @@ eval7( * Lambda: {arg, arg -> expr} * Dictionary: {'key': val, 'key': val} */ - case '{': ret = get_lambda_tv(arg, rettv, evaluate); + case '{': ret = get_lambda_tv(arg, rettv, evalarg); if (ret == NOTDONE) - ret = eval_dict(arg, rettv, flags, FALSE); + ret = eval_dict(arg, rettv, evalarg, FALSE); break; /* * Option value: &name */ - case '&': ret = get_option_tv(arg, rettv, evaluate); + case '&': ret = eval_option(arg, rettv, evaluate); break; /* * Environment variable: $VAR. */ - case '$': ret = get_env_tv(arg, rettv, evaluate); + case '$': ret = eval_env_var(arg, rettv, evaluate); break; /* @@ -2672,15 +2965,19 @@ eval7( /* * nested expression: (expression). */ - case '(': *arg = skipwhite(*arg + 1); - ret = eval1(arg, rettv, flags); // recursive! - if (**arg == ')') - ++*arg; - else if (ret == OK) - { - emsg(_(e_missing_close)); - clear_tv(rettv); - ret = FAIL; + case '(': { + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); + ret = eval1(arg, rettv, evalarg); // recursive! + + *arg = skipwhite_and_linebreak(*arg, evalarg); + if (**arg == ')') + ++*arg; + else if (ret == OK) + { + emsg(_(e_missing_close)); + clear_tv(rettv); + ret = FAIL; + } } break; @@ -2703,14 +3000,17 @@ eval7( ret = FAIL; else { - if (**arg == '(') // recursive! - ret = eval_func(arg, s, len, rettv, flags, NULL); + if (**arg == '(') + // "name(..." recursive! + ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL); else if (flags & EVAL_CONSTANT) ret = FAIL; else if (evaluate) - ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE); + // get value of variable + ret = eval_variable(s, len, rettv, NULL, TRUE, FALSE); else { + // skip the name check_vars(s, len); ret = OK; } @@ -2723,23 +3023,27 @@ eval7( // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) - ret = handle_subscript(arg, rettv, flags, TRUE, - start_leader, &end_leader); + ret = handle_subscript(arg, rettv, evalarg, TRUE); /* * Apply logical NOT and unary '-', from right to left, ignore '+'. */ if (ret == OK && evaluate && end_leader > start_leader) - ret = eval7_leader(rettv, start_leader, &end_leader); + ret = eval7_leader(rettv, FALSE, start_leader, &end_leader); return ret; } /* * Apply the leading "!" and "-" before an eval7 expression to "rettv". + * When "numeric_only" is TRUE only handle "+" and "-". * Adjusts "end_leaderp" until it is at "start_leader". */ static int -eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp) +eval7_leader( + typval_T *rettv, + int numeric_only, + char_u *start_leader, + char_u **end_leaderp) { char_u *end_leader = *end_leaderp; int ret = OK; @@ -2765,6 +3069,11 @@ eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp) --end_leader; if (*end_leader == '!') { + if (numeric_only) + { + ++end_leader; + break; + } #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) f = !f; @@ -2806,6 +3115,7 @@ eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp) static int call_func_rettv( char_u **arg, + evalarg_T *evalarg, typval_T *rettv, int evaluate, dict_T *selfdict, @@ -2842,7 +3152,7 @@ call_func_rettv( funcexe.partial = pt; funcexe.selfdict = selfdict; funcexe.basetv = basetv; - ret = get_func_tv(s, -1, rettv, arg, &funcexe); + ret = get_func_tv(s, -1, rettv, arg, evalarg, &funcexe); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). @@ -2861,9 +3171,11 @@ call_func_rettv( eval_lambda( char_u **arg, typval_T *rettv, - int evaluate, + evalarg_T *evalarg, int verbose) // give error messages { + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); typval_T base = *rettv; int ret; @@ -2871,7 +3183,7 @@ eval_lambda( *arg += 2; rettv->v_type = VAR_UNKNOWN; - ret = get_lambda_tv(arg, rettv, evaluate); + ret = get_lambda_tv(arg, rettv, evalarg); if (ret != OK) return FAIL; else if (**arg != '(') @@ -2887,7 +3199,7 @@ eval_lambda( ret = FAIL; } else - ret = call_func_rettv(arg, rettv, evaluate, NULL, &base); + ret = call_func_rettv(arg, evalarg, rettv, evaluate, NULL, &base); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). @@ -2906,7 +3218,7 @@ eval_lambda( eval_method( char_u **arg, typval_T *rettv, - int evaluate, + evalarg_T *evalarg, int verbose) // give error messages { char_u *name; @@ -2914,6 +3226,8 @@ eval_method( char_u *alias; typval_T base = *rettv; int ret; + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); // Skip over the ->. *arg += 2; @@ -2945,7 +3259,7 @@ eval_method( ret = FAIL; } else - ret = eval_func(arg, name, len, rettv, + ret = eval_func(arg, evalarg, name, len, rettv, evaluate ? EVAL_EVALUATE : 0, &base); } @@ -2966,10 +3280,11 @@ eval_method( eval_index( char_u **arg, typval_T *rettv, - int flags, + evalarg_T *evalarg, int verbose) // give error messages { - int evaluate = flags & EVAL_EVALUATE; + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); int empty1 = FALSE, empty2 = FALSE; typval_T var1, var2; long i; @@ -3035,10 +3350,10 @@ eval_index( * * Get the (first) variable from inside the []. */ - *arg = skipwhite(*arg + 1); + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); if (**arg == ':') empty1 = TRUE; - else if (eval1(arg, &var1, flags) == FAIL) // recursive! + else if (eval1(arg, &var1, evalarg) == FAIL) // recursive! return FAIL; else if (evaluate && tv_get_string_chk(&var1) == NULL) { @@ -3050,13 +3365,14 @@ eval_index( /* * Get the second variable from inside the [:]. */ + *arg = skipwhite_and_linebreak(*arg, evalarg); if (**arg == ':') { range = TRUE; - *arg = skipwhite(*arg + 1); + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); if (**arg == ']') empty2 = TRUE; - else if (eval1(arg, &var2, flags) == FAIL) // recursive! + else if (eval1(arg, &var2, evalarg) == FAIL) // recursive! { if (!empty1) clear_tv(&var1); @@ -3073,6 +3389,7 @@ eval_index( } // Check for the ']'. + *arg = skipwhite_and_linebreak(*arg, evalarg); if (**arg != ']') { if (verbose) @@ -4634,7 +4951,6 @@ make_expanded_name( char_u c1; char_u *retval = NULL; char_u *temp_result; - char_u *nextcmd = NULL; if (expr_end == NULL || in_end == NULL) return NULL; @@ -4643,8 +4959,8 @@ make_expanded_name( c1 = *in_end; *in_end = NUL; - temp_result = eval_to_string(expr_start + 1, &nextcmd, FALSE); - if (temp_result != NULL && nextcmd == NULL) + temp_result = eval_to_string(expr_start + 1, FALSE); + if (temp_result != NULL) { retval = alloc(STRLEN(temp_result) + (expr_start - in_start) + (in_end - expr_end) + 1); @@ -4710,14 +5026,28 @@ eval_isnamec1(int c) handle_subscript( char_u **arg, typval_T *rettv, - int flags, // do more than finding the end - int verbose, // give error messages - char_u *start_leader, // start of '!' and '-' prefixes - char_u **end_leaderp) // end of '!' and '-' prefixes + evalarg_T *evalarg, + int verbose) // give error messages { - int evaluate = flags & EVAL_EVALUATE; + int evaluate = evalarg != NULL + && (evalarg->eval_flags & EVAL_EVALUATE); int ret = OK; dict_T *selfdict = NULL; + int check_white = TRUE; + + // When at the end of the line and ".name" follows in the next line then + // consume the line break. Only when rettv is a dict. + if (rettv->v_type == VAR_DICT) + { + int getnext; + char_u *p = eval_next_non_blank(*arg, evalarg, &getnext); + + if (getnext && *p == '.' && ASCII_ISALPHA(p[1])) + { + *arg = eval_next_line(evalarg); + check_white = FALSE; + } + } // "." is ".name" lookup when we found a dict or when evaluating and // scriptversion is at least 2, where string concatenation is "..". @@ -4729,12 +5059,13 @@ handle_subscript( && current_sctx.sc_version >= 2))) || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC || rettv->v_type == VAR_PARTIAL))) - && !VIM_ISWHITE(*(*arg - 1))) + && (!check_white || !VIM_ISWHITE(*(*arg - 1)))) || (**arg == '-' && (*arg)[1] == '>'))) { if (**arg == '(') { - ret = call_func_rettv(arg, rettv, evaluate, selfdict, NULL); + ret = call_func_rettv(arg, evalarg, rettv, evaluate, + selfdict, NULL); // Stop the expression evaluation when immediately aborting on // error, or when an interrupt occurred or an exception was thrown @@ -4750,18 +5081,14 @@ handle_subscript( } else if (**arg == '-') { - // Expression "-1.0->method()" applies the leader "-" before - // applying ->. - if (evaluate && *end_leaderp > start_leader) - ret = eval7_leader(rettv, start_leader, end_leaderp); if (ret == OK) { if ((*arg)[2] == '{') // expr->{lambda}() - ret = eval_lambda(arg, rettv, evaluate, verbose); + ret = eval_lambda(arg, rettv, evalarg, verbose); else // expr->name() - ret = eval_method(arg, rettv, evaluate, verbose); + ret = eval_method(arg, rettv, evalarg, verbose); } } else // **arg == '[' || **arg == '.' @@ -4775,7 +5102,7 @@ handle_subscript( } else selfdict = NULL; - if (eval_index(arg, rettv, flags, verbose) == FAIL) + if (eval_index(arg, rettv, evalarg, verbose) == FAIL) { clear_tv(rettv); ret = FAIL; @@ -4947,6 +5274,9 @@ ex_echo(exarg_T *eap) int atstart = TRUE; int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; + evalarg_T evalarg; + + fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eap->skip) ++emsg_skip; @@ -4957,7 +5287,7 @@ ex_echo(exarg_T *eap) need_clr_eos = needclr; p = arg; - if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) + if (eval1(&arg, &rettv, &evalarg) == FAIL) { /* * Report the invalid expression unless the expression evaluation @@ -4979,6 +5309,7 @@ ex_echo(exarg_T *eap) arg = skipwhite(arg); } eap->nextcmd = check_nextcmd(arg); + clear_evalarg(&evalarg, eap); if (eap->skip) --emsg_skip; @@ -5033,7 +5364,7 @@ ex_execute(exarg_T *eap) ++emsg_skip; while (!ends_excmd2(eap->cmd, arg) || *arg == '"') { - ret = eval1_emsg(&arg, &rettv, !eap->skip); + ret = eval1_emsg(&arg, &rettv, eap); if (ret == FAIL) break; diff --git a/src/evalfunc.c b/src/evalfunc.c index 3e3fe85cbd..eb6bcc1fa6 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -347,6 +347,52 @@ ret_first_arg(int argcount, type_T **argtypes) return &t_void; } +/* + * Used for getqflist(): returns list if there is no argument, dict if there is + * one. + */ + static type_T * +ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED) +{ + if (argcount > 0) + return &t_dict_any; + return &t_list_dict_any; +} + +/* + * Used for getloclist(): returns list if there is one argument, dict if there + * are two. + */ + static type_T * +ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED) +{ + if (argcount > 1) + return &t_dict_any; + return &t_list_dict_any; +} + + static type_T * +ret_argv(int argcount, type_T **argtypes UNUSED) +{ + // argv() returns list of strings + if (argcount == 0) + return &t_list_string; + + // argv(0) returns a string, but argv(-1] returns a list + return &t_any; +} + + static type_T * +ret_remove(int argcount UNUSED, type_T **argtypes) +{ + if (argtypes[0]->tt_type == VAR_LIST + || argtypes[0]->tt_type == VAR_DICT) + return argtypes[0]->tt_member; + if (argtypes[0]->tt_type == VAR_BLOB) + return &t_number; + return &t_any; +} + static type_T *ret_f_function(int argcount, type_T **argtypes); /* @@ -417,14 +463,14 @@ static funcentry_T global_functions[] = { {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)}, {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)}, - {"add", 2, 2, FEARG_1, ret_any, f_add}, + {"add", 2, 2, FEARG_1, ret_first_arg, f_add}, {"and", 2, 2, FEARG_1, ret_number, f_and}, {"append", 2, 2, FEARG_LAST, ret_number, f_append}, {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline}, {"argc", 0, 1, 0, ret_number, f_argc}, {"argidx", 0, 0, 0, ret_number, f_argidx}, {"arglistid", 0, 2, 0, ret_number, f_arglistid}, - {"argv", 0, 2, 0, ret_any, f_argv}, + {"argv", 0, 2, 0, ret_argv, f_argv}, {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)}, {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps}, {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal}, @@ -509,7 +555,7 @@ static funcentry_T global_functions[] = {"complete_check", 0, 0, 0, ret_number, f_complete_check}, {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info}, {"confirm", 1, 4, FEARG_1, ret_number, f_confirm}, - {"copy", 1, 1, FEARG_1, ret_any, f_copy}, + {"copy", 1, 1, FEARG_1, ret_first_arg, f_copy}, {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)}, {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)}, {"count", 2, 4, FEARG_1, ret_number, f_count}, @@ -522,7 +568,7 @@ static funcentry_T global_functions[] = NULL #endif }, - {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy}, + {"deepcopy", 1, 2, FEARG_1, ret_first_arg, f_deepcopy}, {"delete", 1, 2, FEARG_1, ret_number, f_delete}, {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline}, {"did_filetype", 0, 0, 0, ret_number, f_did_filetype}, @@ -541,12 +587,12 @@ static funcentry_T global_functions[] = {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)}, {"expand", 1, 3, FEARG_1, ret_any, f_expand}, {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd}, - {"extend", 2, 3, FEARG_1, ret_any, f_extend}, + {"extend", 2, 3, FEARG_1, ret_first_arg, f_extend}, {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys}, {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable}, {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable}, - {"filter", 2, 2, FEARG_1, ret_any, f_filter}, + {"filter", 2, 2, FEARG_1, ret_first_arg, f_filter}, {"finddir", 1, 3, FEARG_1, ret_string, f_finddir}, {"findfile", 1, 3, FEARG_1, ret_string, f_findfile}, {"flatten", 1, 2, FEARG_1, ret_list_any, f_flatten}, @@ -588,13 +634,13 @@ static funcentry_T global_functions[] = {"getimstatus", 0, 0, 0, ret_number, f_getimstatus}, {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist}, {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline}, - {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist}, + {"getloclist", 1, 2, 0, ret_list_or_dict_1, f_getloclist}, {"getmarklist", 0, 1, FEARG_1, ret_list_dict_any, f_getmarklist}, {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches}, {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos}, {"getpid", 0, 0, 0, ret_number, f_getpid}, {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos}, - {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist}, + {"getqflist", 0, 1, 0, ret_list_or_dict_0, f_getqflist}, {"getreg", 0, 3, FEARG_1, ret_string, f_getreg}, {"getreginfo", 0, 1, FEARG_1, ret_dict_any, f_getreginfo}, {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype}, @@ -632,7 +678,7 @@ static funcentry_T global_functions[] = {"inputrestore", 0, 0, 0, ret_number, f_inputrestore}, {"inputsave", 0, 0, 0, ret_number, f_inputsave}, {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret}, - {"insert", 2, 3, FEARG_1, ret_any, f_insert}, + {"insert", 2, 3, FEARG_1, ret_first_arg, f_insert}, {"interrupt", 0, 0, 0, ret_void, f_interrupt}, {"invert", 1, 1, FEARG_1, ret_number, f_invert}, {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory}, @@ -791,12 +837,12 @@ static funcentry_T global_functions[] = {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek}, {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read}, {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send}, - {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver}, - {"remove", 2, 3, FEARG_1, ret_any, f_remove}, + {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver}, + {"remove", 2, 3, FEARG_1, ret_remove, f_remove}, {"rename", 2, 2, FEARG_1, ret_number, f_rename}, - {"repeat", 2, 2, FEARG_1, ret_any, f_repeat}, + {"repeat", 2, 2, FEARG_1, ret_first_arg, f_repeat}, {"resolve", 1, 1, FEARG_1, ret_string, f_resolve}, - {"reverse", 1, 1, FEARG_1, ret_any, f_reverse}, + {"reverse", 1, 1, FEARG_1, ret_first_arg, f_reverse}, {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)}, {"rubyeval", 1, 1, FEARG_1, ret_any, #ifdef FEAT_RUBY @@ -2084,7 +2130,7 @@ f_eval(typval_T *argvars, typval_T *rettv) s = skipwhite(s); p = s; - if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL) + if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); @@ -2300,7 +2346,7 @@ f_exists(typval_T *argvars, typval_T *rettv) } else if (*p == '&' || *p == '+') // option { - n = (get_option_tv(&p, NULL, TRUE) == OK); + n = (eval_option(&p, NULL, TRUE) == OK); if (*skipwhite(p) != NUL) n = FALSE; // trailing garbage } @@ -6307,7 +6353,7 @@ f_getreginfo(typval_T *argvars, typval_T *rettv) list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST); if (list == NULL) return; - dict_add_list(dict, "regcontents", list); + (void)dict_add_list(dict, "regcontents", list); buf[0] = NUL; buf[1] = NUL; @@ -6320,12 +6366,12 @@ f_getreginfo(typval_T *argvars, typval_T *rettv) reglen + 1); break; } - dict_add_string(dict, (char *)"regtype", buf); + (void)dict_add_string(dict, (char *)"regtype", buf); buf[0] = get_register_name(get_unname_register()); buf[1] = NUL; if (regname == '"') - dict_add_string(dict, (char *)"points_to", buf); + (void)dict_add_string(dict, (char *)"points_to", buf); else { dictitem_T *item = dictitem_alloc((char_u *)"isunnamed"); @@ -6335,7 +6381,7 @@ f_getreginfo(typval_T *argvars, typval_T *rettv) item->di_tv.v_type = VAR_SPECIAL; item->di_tv.vval.v_number = regname == buf[0] ? VVAL_TRUE : VVAL_FALSE; - dict_add(dict, item); + (void)dict_add(dict, item); } } } diff --git a/src/evalvars.c b/src/evalvars.c index 1ffe8a594b..0cbc612f45 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -437,7 +437,7 @@ eval_spell_expr(char_u *badword, char_u *expr) if (p_verbose == 0) ++emsg_off; - if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) + if (eval1(&p, &rettv, &EVALARG_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); @@ -776,7 +776,7 @@ ex_let(exarg_T *eap) } else { - int eval_flags; + evalarg_T evalarg; rettv.v_type = VAR_UNKNOWN; i = FAIL; @@ -799,14 +799,22 @@ ex_let(exarg_T *eap) if (eap->skip) ++emsg_skip; - eval_flags = eap->skip ? 0 : EVAL_EVALUATE; - i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); + CLEAR_FIELD(evalarg); + evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE; + if (getline_equal(eap->getline, eap->cookie, getsourceline)) + { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } + i = eval0(expr, &rettv, eap, &evalarg); + if (eap->skip) + --emsg_skip; + clear_evalarg(&evalarg, eap); } if (eap->skip) { if (i != FAIL) clear_tv(&rettv); - --emsg_skip; } else if (i != FAIL) { @@ -1118,14 +1126,14 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first) { if (tofree != NULL) name = tofree; - if (get_var_tv(name, len, &tv, NULL, TRUE, FALSE) == FAIL) + if (eval_variable(name, len, &tv, NULL, TRUE, FALSE) == FAIL) error = TRUE; else { // handle d.key, l[idx], f(expr) arg_subsc = arg; - if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE, - name, &name) == FAIL) + if (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, TRUE) + == FAIL) error = TRUE; else { @@ -2359,7 +2367,7 @@ set_cmdarg(exarg_T *eap, char_u *oldarg) * Return OK or FAIL. If OK is returned "rettv" must be cleared. */ int -get_var_tv( +eval_variable( char_u *name, int len, // length of "name" typval_T *rettv, // NULL when only checking existence @@ -2846,7 +2854,7 @@ set_var( typval_T *tv, int copy) // make copy of value in "tv" { - set_var_const(name, NULL, tv, copy, 0); + set_var_const(name, NULL, tv, copy, LET_NO_COMMAND); } /* @@ -3200,7 +3208,7 @@ getwinvar( done = TRUE; } } - else if (get_option_tv(&varname, rettv, 1) == OK) + else if (eval_option(&varname, rettv, 1) == OK) // window-local-option done = TRUE; } @@ -3336,12 +3344,11 @@ var_exists(char_u *var) { if (tofree != NULL) name = tofree; - n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK); + n = (eval_variable(name, len, &tv, NULL, FALSE, TRUE) == OK); if (n) { // handle d.key, l[idx], f(expr) - n = (handle_subscript(&var, &tv, EVAL_EVALUATE, - FALSE, name, &name) == OK); + n = (handle_subscript(&var, &tv, &EVALARG_EVALUATE, FALSE) == OK); if (n) clear_tv(&tv); } @@ -3604,7 +3611,7 @@ f_getbufvar(typval_T *argvars, typval_T *rettv) done = TRUE; } } - else if (get_option_tv(&varname, rettv, TRUE) == OK) + else if (eval_option(&varname, rettv, TRUE) == OK) // buffer-local-option done = TRUE; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 5ff207ee3b..e91a604104 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1847,6 +1847,9 @@ struct exarg char_u *nextcmd; // next command (NULL if none) char_u *cmd; // the name of the command (except for :make) char_u **cmdlinep; // pointer to pointer of allocated cmdline +#ifdef FEAT_EVAL + char_u *cmdline_tofree; // free later +#endif cmdidx_T cmdidx; // the index for the command long argt; // flags for the command int skip; // don't execute the command, only parse it diff --git a/src/ex_docmd.c b/src/ex_docmd.c index e4d1ad9fee..1aa1ae7128 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -25,7 +25,6 @@ static char_u *do_one_cmd(char_u **, int, cstack_T *, char_u *(*fgetline)(int, v static char_u *do_one_cmd(char_u **, int, char_u *(*fgetline)(int, void *, int, int), void *cookie); static int if_level = 0; // depth in :if #endif -static void free_cmdmod(void); static void append_command(char_u *cmd); #ifndef FEAT_MENU @@ -635,6 +634,7 @@ do_cmdline( cstack_T cstack; // conditional stack garray_T lines_ga; // keep lines for ":while"/":for" int current_line = 0; // active line in lines_ga + int current_line_before = 0; char_u *fname = NULL; // function or script name linenr_T *breakpoint = NULL; // ptr to breakpoint field in cookie int *dbg_tick = NULL; // ptr to dbg_tick field in cookie @@ -857,27 +857,6 @@ do_cmdline( } # endif } - - if (cstack.cs_looplevel > 0) - { - // Inside a while/for loop we need to store the lines and use them - // again. Pass a different "fgetline" function to do_one_cmd() - // below, so that it stores lines in or reads them from - // "lines_ga". Makes it possible to define a function inside a - // while/for loop. - cmd_getline = get_loop_line; - cmd_cookie = (void *)&cmd_loop_cookie; - cmd_loop_cookie.lines_gap = &lines_ga; - cmd_loop_cookie.current_line = current_line; - cmd_loop_cookie.getline = fgetline; - cmd_loop_cookie.cookie = cookie; - cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); - } - else - { - cmd_getline = fgetline; - cmd_cookie = cookie; - } #endif // 2. If no line given, get an allocated line with fgetline(). @@ -935,21 +914,44 @@ do_cmdline( #ifdef FEAT_EVAL /* - * Save the current line when inside a ":while" or ":for", and when - * the command looks like a ":while" or ":for", because we may need it - * later. When there is a '|' and another command, it is stored - * separately, because we need to be able to jump back to it from an + * Inside a while/for loop, and when the command looks like a ":while" + * or ":for", the line is stored, because we may need it later when + * looping. + * + * When there is a '|' and another command, it is stored separately, + * because we need to be able to jump back to it from an * :endwhile/:endfor. + * + * Pass a different "fgetline" function to do_one_cmd() below, + * that it stores lines in or reads them from "lines_ga". Makes it + * possible to define a function inside a while/for loop and handles + * line continuation. */ - if (current_line == lines_ga.ga_len - && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) + if ((cstack.cs_looplevel > 0 || has_loop_cmd(next_cmdline))) { - if (store_loop_line(&lines_ga, next_cmdline) == FAIL) + cmd_getline = get_loop_line; + cmd_cookie = (void *)&cmd_loop_cookie; + cmd_loop_cookie.lines_gap = &lines_ga; + cmd_loop_cookie.current_line = current_line; + cmd_loop_cookie.getline = fgetline; + cmd_loop_cookie.cookie = cookie; + cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); + + // Save the current line when encountering it the first time. + if (current_line == lines_ga.ga_len + && store_loop_line(&lines_ga, next_cmdline) == FAIL) { retval = FAIL; break; } + current_line_before = current_line; } + else + { + cmd_getline = fgetline; + cmd_cookie = cookie; + } + did_endif = FALSE; #endif @@ -1084,7 +1086,7 @@ do_cmdline( else if (cstack.cs_lflags & CSL_HAD_LOOP) { cstack.cs_lflags &= ~CSL_HAD_LOOP; - cstack.cs_line[cstack.cs_idx] = current_line - 1; + cstack.cs_line[cstack.cs_idx] = current_line_before; } } @@ -1521,7 +1523,7 @@ getline_cookie( { #ifdef FEAT_EVAL char_u *(*gp)(int, void *, int, int); - struct loop_cookie *cp; + struct loop_cookie *cp; // When "fgetline" is "get_loop_line()" use the "cookie" to find the // cookie that's originally used to obtain the lines. This may be nested @@ -1539,6 +1541,41 @@ getline_cookie( #endif } +#if defined(FEAT_EVAL) || defined(PROT) +/* + * Get the next line source line without advancing. + */ + char_u * +getline_peek( + char_u *(*fgetline)(int, void *, int, int) UNUSED, + void *cookie) // argument for fgetline() +{ + char_u *(*gp)(int, void *, int, int); + struct loop_cookie *cp; + wcmd_T *wp; + + // When "fgetline" is "get_loop_line()" use the "cookie" to find the + // cookie that's originally used to obtain the lines. This may be nested + // several levels. + gp = fgetline; + cp = (struct loop_cookie *)cookie; + while (gp == get_loop_line) + { + if (cp->current_line + 1 < cp->lines_gap->ga_len) + { + // executing lines a second time, use the stored copy + wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line + 1; + return wp->line; + } + gp = cp->getline; + cp = cp->cookie; + } + if (gp == getsourceline) + return source_nextline(cp); + return NULL; +} +#endif + /* * Helper function to apply an offset for buffer commands, i.e. ":bdelete", @@ -2579,32 +2616,10 @@ doend: ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); #endif - if (ea.verbose_save >= 0) - p_verbose = ea.verbose_save; - - free_cmdmod(); + undo_cmdmod(&ea, save_msg_scroll); cmdmod = save_cmdmod; reg_executing = save_reg_executing; - if (ea.save_msg_silent != -1) - { - // messages could be enabled for a serious error, need to check if the - // counters don't become negative - if (!did_emsg || msg_silent > ea.save_msg_silent) - msg_silent = ea.save_msg_silent; - emsg_silent -= ea.did_esilent; - if (emsg_silent < 0) - emsg_silent = 0; - // Restore msg_scroll, it's set by file I/O commands, even when no - // message is actually displayed. - msg_scroll = save_msg_scroll; - - // "silent reg" or "silent echo x" inside "redir" leaves msg_col - // somewhere in the line. Put it back in the first column. - if (redirecting()) - msg_col = 0; - } - #ifdef HAVE_SANDBOX if (ea.did_sandbox) --sandbox; @@ -2615,6 +2630,7 @@ doend: #ifdef FEAT_EVAL --ex_nesting_level; + vim_free(ea.cmdline_tofree); #endif return ea.nextcmd; @@ -2894,11 +2910,14 @@ parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only) } /* - * Free contents of "cmdmod". + * Unod and free contents of "cmdmod". */ - static void -free_cmdmod(void) + void +undo_cmdmod(exarg_T *eap, int save_msg_scroll) { + if (eap->verbose_save >= 0) + p_verbose = eap->verbose_save; + if (cmdmod.save_ei != NULL) { // Restore 'eventignore' to the value before ":noautocmd". @@ -2909,6 +2928,25 @@ free_cmdmod(void) if (cmdmod.filter_regmatch.regprog != NULL) vim_regfree(cmdmod.filter_regmatch.regprog); + + if (eap->save_msg_silent != -1) + { + // messages could be enabled for a serious error, need to check if the + // counters don't become negative + if (!did_emsg || msg_silent > eap->save_msg_silent) + msg_silent = eap->save_msg_silent; + emsg_silent -= eap->did_esilent; + if (emsg_silent < 0) + emsg_silent = 0; + // Restore msg_scroll, it's set by file I/O commands, even when no + // message is actually displayed. + msg_scroll = save_msg_scroll; + + // "silent reg" or "silent echo x" inside "redir" leaves msg_col + // somewhere in the line. Put it back in the first column. + if (redirecting()) + msg_col = 0; + } } /* @@ -3186,8 +3224,9 @@ find_ex_command( * "lvar = value", "lvar(arg)", "[1, 2 3]->Func()" */ p = eap->cmd; - if (lookup != NULL && (*p == '(' - || ((p = to_name_const_end(eap->cmd)) > eap->cmd && *p != NUL))) + if (lookup != NULL && (*p == '(' || *p == '{' + || ((p = to_name_const_end(eap->cmd)) > eap->cmd && *p != NUL) + || *p == '[')) { int oplen; int heredoc; @@ -3197,8 +3236,10 @@ find_ex_command( // "g:varname" is an expression. // "varname->expr" is an expression. // "(..." is an expression. + // "{..." is an dict expression. if (*p == '(' - || *p == '[' + || *p == '{' + || (*p == '[' && p > eap->cmd) || p[1] == ':' || (*p == '-' && p[1] == '>')) { @@ -3206,12 +3247,24 @@ find_ex_command( return eap->cmd; } + // "[...]->Method()" is a list expression, but "[a, b] = Func()" is + // an assignment. + // If there is no line break inside the "[...]" then "p" is advanced to + // after the "]" by to_name_const_end(): check if a "=" follows. + // If "[...]" has a line break "p" still points at the "[" and it can't + // be an assignment. + if (*eap->cmd == '[' && (p == eap->cmd || *skipwhite(p) != '=')) + { + eap->cmdidx = CMD_eval; + return eap->cmd; + } + + // Recognize an assignment if we recognize the variable name: + // "g:var = expr" + // "var = expr" where "var" is a local var name. oplen = assignment_len(skipwhite(p), &heredoc); if (oplen > 0) { - // Recognize an assignment if we recognize the variable name: - // "g:var = expr" - // "var = expr" where "var" is a local var name. if (((p - eap->cmd) > 2 && eap->cmd[1] == ':') || lookup(eap->cmd, p - eap->cmd, cctx) != NULL) { @@ -4918,7 +4971,7 @@ ex_colorscheme(exarg_T *eap) if (expr != NULL) { ++emsg_off; - p = eval_to_string(expr, NULL, FALSE); + p = eval_to_string(expr, FALSE); --emsg_off; vim_free(expr); } @@ -5183,6 +5236,13 @@ ex_win_close( int need_hide; buf_T *buf = win->w_buffer; + // Never close the autocommand window. + if (win == aucmd_win) + { + emsg(_(e_autocmd_close)); + return; + } + need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); if (need_hide && !buf_hide(buf) && !forceit) { diff --git a/src/ex_eval.c b/src/ex_eval.c index a13f844b14..061bd1a649 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -895,10 +895,14 @@ report_discard_pending(int pending, void *value) ex_eval(exarg_T *eap) { typval_T tv; + evalarg_T evalarg; - if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) - == OK) + fill_evalarg_from_eap(&evalarg, eap, eap->skip); + + if (eval0(eap->arg, &tv, eap, &evalarg) == OK) clear_tv(&tv); + + clear_evalarg(&evalarg, eap); } /* @@ -926,7 +930,7 @@ ex_if(exarg_T *eap) skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0 && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)); - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); if (!skip && !error) { @@ -1038,7 +1042,7 @@ ex_else(exarg_T *eap) if (eap->cmdidx == CMD_elseif) { - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); // When throwing error exceptions, we want to throw always the first // of several errors in a row. This is what actually happens when @@ -1100,11 +1104,20 @@ ex_while(exarg_T *eap) /* * ":while bool-expr" */ - result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + result = eval_to_bool(eap->arg, &error, eap, skip); } else { - void *fi; + void *fi; + evalarg_T evalarg; + + CLEAR_FIELD(evalarg); + evalarg.eval_flags = skip ? 0 : EVAL_EVALUATE; + if (getline_equal(eap->getline, eap->cookie, getsourceline)) + { + evalarg.eval_getline = eap->getline; + evalarg.eval_cookie = eap->cookie; + } /* * ":for var in list-expr" @@ -1115,11 +1128,14 @@ ex_while(exarg_T *eap) // previously evaluated list. fi = cstack->cs_forinfo[cstack->cs_idx]; error = FALSE; + + // the "in expr" is not used, skip over it + skip_for_lines(fi, &evalarg); } else { // Evaluate the argument and get the info in a structure. - fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip); + fi = eval_for_line(eap->arg, &error, eap, &evalarg); cstack->cs_forinfo[cstack->cs_idx] = fi; } @@ -1134,6 +1150,7 @@ ex_while(exarg_T *eap) free_for_info(fi); cstack->cs_forinfo[cstack->cs_idx] = NULL; } + clear_evalarg(&evalarg, eap); } /* @@ -1319,7 +1336,7 @@ ex_throw(exarg_T *eap) char_u *value; if (*arg != NUL && *arg != '|' && *arg != '\n') - value = eval_to_string_skip(arg, &eap->nextcmd, eap->skip); + value = eval_to_string_skip(arg, eap, eap->skip); else { emsg(_(e_argreq)); diff --git a/src/fileio.c b/src/fileio.c index 8130000247..451fa2bcf3 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -52,10 +52,14 @@ filemess( if (msg_silent != 0) return; msg_add_fname(buf, name); // put file name in IObuff with quotes + // If it's extremely long, truncate it. - if (STRLEN(IObuff) > IOSIZE - 80) - IObuff[IOSIZE - 80] = NUL; - STRCAT(IObuff, s); + if (STRLEN(IObuff) > IOSIZE - 100) + IObuff[IOSIZE - 100] = NUL; + + // Avoid an over-long translation to cause trouble. + STRNCAT(IObuff, s, 99); + /* * For the first message may have to start a new line. * For further ones overwrite the previous one, reset msg_scroll before @@ -3035,13 +3039,13 @@ msg_add_lines( *p++ = ' '; if (shortmess(SHM_LINES)) vim_snprintf((char *)p, IOSIZE - (p - IObuff), - "%ldL, %lldC", lnum, (varnumber_T)nchars); + "%ldL, %lldB", lnum, (varnumber_T)nchars); else { sprintf((char *)p, NGETTEXT("%ld line, ", "%ld lines, ", lnum), lnum); p += STRLEN(p); vim_snprintf((char *)p, IOSIZE - (p - IObuff), - NGETTEXT("%lld character", "%lld characters", nchars), + NGETTEXT("%lld byte", "%lld bytes", nchars), (varnumber_T)nchars); } } diff --git a/src/filepath.c b/src/filepath.c index c00b5a935f..cdd69035b6 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -3083,7 +3083,7 @@ expand_backtick( #ifdef FEAT_EVAL if (*cmd == '=') // `={expr}`: Expand expression - buffer = eval_to_string(cmd + 1, &p, TRUE); + buffer = eval_to_string(cmd + 1, TRUE); else #endif buffer = get_cmd_output(cmd, NULL, @@ -3813,8 +3813,13 @@ gen_expand_wildcards( vim_free(p); } + // When returning FAIL the array must be freed here. + if (retval == FAIL) + ga_clear(&ga); + *num_file = ga.ga_len; - *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data : (char_u **)""; + *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data + : (char_u **)_("no matches"); recursive = FALSE; diff --git a/src/findfile.c b/src/findfile.c index b153ed010c..190fc69dc6 100644 --- a/src/findfile.c +++ b/src/findfile.c @@ -2079,7 +2079,7 @@ eval_includeexpr(char_u *ptr, int len) char_u *res; set_vim_var_string(VV_FNAME, ptr, len); - res = eval_to_string_safe(curbuf->b_p_inex, NULL, + res = eval_to_string_safe(curbuf->b_p_inex, was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL)); set_vim_var_string(VV_FNAME, NULL, 0); return res; diff --git a/src/fold.c b/src/fold.c index d91203c75c..043037fa64 100644 --- a/src/fold.c +++ b/src/fold.c @@ -1928,7 +1928,7 @@ get_foldtext( curbuf = wp->w_buffer; ++emsg_silent; // handle exceptions, but don't display errors - text = eval_to_string_safe(wp->w_p_fdt, NULL, + text = eval_to_string_safe(wp->w_p_fdt, was_set_insecurely((char_u *)"foldtext", OPT_LOCAL)); --emsg_silent; diff --git a/src/globals.h b/src/globals.h index 7425e8367e..113d779b96 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1770,6 +1770,7 @@ EXTERN char e_float_as_string[] INIT(= N_("E806: using Float as a String")); #endif EXTERN char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\"")); EXTERN char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior")); +EXTERN char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd or popup window")); #ifdef FEAT_MENU EXTERN char e_menuothermode[] INIT(= N_("E328: Menu only exists in another mode")); #endif @@ -1885,6 +1886,13 @@ EXTERN char windowsVersion[20] INIT(= {0}); // Used for lv_first in a non-materialized range() list. EXTERN listitem_T range_list_item; + +// Passed to an eval() function to enable evaluation. +EXTERN evalarg_T EVALARG_EVALUATE +# ifdef DO_INIT + = {EVAL_EVALUATE, 0, NULL, NULL, {0, 0, 0, 0, NULL}, NULL} +# endif + ; #endif #ifdef MSWIN diff --git a/src/gui_xim.c b/src/gui_xim.c index 9723304d55..3ae6865331 100644 --- a/src/gui_xim.c +++ b/src/gui_xim.c @@ -57,7 +57,7 @@ xim_log(char *s, ...) } #endif -#ifdef FEAT_GUI +#if defined(FEAT_GUI_MSWIN) # define USE_IMACTIVATEFUNC (!gui.in_use && *p_imaf != NUL) # define USE_IMSTATUSFUNC (!gui.in_use && *p_imsf != NUL) #else diff --git a/src/highlight.c b/src/highlight.c index 261afd825a..65b240205e 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -9,7 +9,6 @@ /* * Highlighting stuff. - * Includes highlighting matches. */ #include "vim.h" @@ -3695,1347 +3694,3 @@ free_highlight_fonts(void) # endif } #endif - - -#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) - -# define SEARCH_HL_PRIORITY 0 - -/* - * Add match to the match list of window 'wp'. The pattern 'pat' will be - * highlighted with the group 'grp' with priority 'prio'. - * Optionally, a desired ID 'id' can be specified (greater than or equal to 1). - * If no particular ID is desired, -1 must be specified for 'id'. - * Return ID of added match, -1 on failure. - */ - static int -match_add( - win_T *wp, - char_u *grp, - char_u *pat, - int prio, - int id, - list_T *pos_list, - char_u *conceal_char UNUSED) // pointer to conceal replacement char -{ - matchitem_T *cur; - matchitem_T *prev; - matchitem_T *m; - int hlg_id; - regprog_T *regprog = NULL; - int rtype = SOME_VALID; - - if (*grp == NUL || (pat != NULL && *pat == NUL)) - return -1; - if (id < -1 || id == 0) - { - semsg(_("E799: Invalid ID: %d (must be greater than or equal to 1)"), - id); - return -1; - } - if (id != -1) - { - cur = wp->w_match_head; - while (cur != NULL) - { - if (cur->id == id) - { - semsg(_("E801: ID already taken: %d"), id); - return -1; - } - cur = cur->next; - } - } - if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0) - { - semsg(_(e_nogroup), grp); - return -1; - } - if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) - { - semsg(_(e_invarg2), pat); - return -1; - } - - // Find available match ID. - while (id == -1) - { - cur = wp->w_match_head; - while (cur != NULL && cur->id != wp->w_next_match_id) - cur = cur->next; - if (cur == NULL) - id = wp->w_next_match_id; - wp->w_next_match_id++; - } - - // Build new match. - m = ALLOC_CLEAR_ONE(matchitem_T); - m->id = id; - m->priority = prio; - m->pattern = pat == NULL ? NULL : vim_strsave(pat); - m->hlg_id = hlg_id; - m->match.regprog = regprog; - m->match.rmm_ic = FALSE; - m->match.rmm_maxcol = 0; -# if defined(FEAT_CONCEAL) - m->conceal_char = 0; - if (conceal_char != NULL) - m->conceal_char = (*mb_ptr2char)(conceal_char); -# endif - - // Set up position matches - if (pos_list != NULL) - { - linenr_T toplnum = 0; - linenr_T botlnum = 0; - listitem_T *li; - int i; - - CHECK_LIST_MATERIALIZE(pos_list); - for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH; - i++, li = li->li_next) - { - linenr_T lnum = 0; - colnr_T col = 0; - int len = 1; - list_T *subl; - listitem_T *subli; - int error = FALSE; - - if (li->li_tv.v_type == VAR_LIST) - { - subl = li->li_tv.vval.v_list; - if (subl == NULL) - goto fail; - subli = subl->lv_first; - if (subli == NULL) - goto fail; - lnum = tv_get_number_chk(&subli->li_tv, &error); - if (error == TRUE) - goto fail; - if (lnum == 0) - { - --i; - continue; - } - m->pos.pos[i].lnum = lnum; - subli = subli->li_next; - if (subli != NULL) - { - col = tv_get_number_chk(&subli->li_tv, &error); - if (error == TRUE) - goto fail; - subli = subli->li_next; - if (subli != NULL) - { - len = tv_get_number_chk(&subli->li_tv, &error); - if (error == TRUE) - goto fail; - } - } - m->pos.pos[i].col = col; - m->pos.pos[i].len = len; - } - else if (li->li_tv.v_type == VAR_NUMBER) - { - if (li->li_tv.vval.v_number == 0) - { - --i; - continue; - } - m->pos.pos[i].lnum = li->li_tv.vval.v_number; - m->pos.pos[i].col = 0; - m->pos.pos[i].len = 0; - } - else - { - emsg(_("E290: List or number required")); - goto fail; - } - if (toplnum == 0 || lnum < toplnum) - toplnum = lnum; - if (botlnum == 0 || lnum >= botlnum) - botlnum = lnum + 1; - } - - // Calculate top and bottom lines for redrawing area - if (toplnum != 0) - { - if (wp->w_buffer->b_mod_set) - { - if (wp->w_buffer->b_mod_top > toplnum) - wp->w_buffer->b_mod_top = toplnum; - if (wp->w_buffer->b_mod_bot < botlnum) - wp->w_buffer->b_mod_bot = botlnum; - } - else - { - wp->w_buffer->b_mod_set = TRUE; - wp->w_buffer->b_mod_top = toplnum; - wp->w_buffer->b_mod_bot = botlnum; - wp->w_buffer->b_mod_xlines = 0; - } - m->pos.toplnum = toplnum; - m->pos.botlnum = botlnum; - rtype = VALID; - } - } - - // Insert new match. The match list is in ascending order with regard to - // the match priorities. - cur = wp->w_match_head; - prev = cur; - while (cur != NULL && prio >= cur->priority) - { - prev = cur; - cur = cur->next; - } - if (cur == prev) - wp->w_match_head = m; - else - prev->next = m; - m->next = cur; - - redraw_win_later(wp, rtype); - return id; - -fail: - vim_free(m); - return -1; -} - -/* - * Delete match with ID 'id' in the match list of window 'wp'. - * Print error messages if 'perr' is TRUE. - */ - static int -match_delete(win_T *wp, int id, int perr) -{ - matchitem_T *cur = wp->w_match_head; - matchitem_T *prev = cur; - int rtype = SOME_VALID; - - if (id < 1) - { - if (perr == TRUE) - semsg(_("E802: Invalid ID: %d (must be greater than or equal to 1)"), - id); - return -1; - } - while (cur != NULL && cur->id != id) - { - prev = cur; - cur = cur->next; - } - if (cur == NULL) - { - if (perr == TRUE) - semsg(_("E803: ID not found: %d"), id); - return -1; - } - if (cur == prev) - wp->w_match_head = cur->next; - else - prev->next = cur->next; - vim_regfree(cur->match.regprog); - vim_free(cur->pattern); - if (cur->pos.toplnum != 0) - { - if (wp->w_buffer->b_mod_set) - { - if (wp->w_buffer->b_mod_top > cur->pos.toplnum) - wp->w_buffer->b_mod_top = cur->pos.toplnum; - if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) - wp->w_buffer->b_mod_bot = cur->pos.botlnum; - } - else - { - wp->w_buffer->b_mod_set = TRUE; - wp->w_buffer->b_mod_top = cur->pos.toplnum; - wp->w_buffer->b_mod_bot = cur->pos.botlnum; - wp->w_buffer->b_mod_xlines = 0; - } - rtype = VALID; - } - vim_free(cur); - redraw_win_later(wp, rtype); - return 0; -} - -/* - * Delete all matches in the match list of window 'wp'. - */ - void -clear_matches(win_T *wp) -{ - matchitem_T *m; - - while (wp->w_match_head != NULL) - { - m = wp->w_match_head->next; - vim_regfree(wp->w_match_head->match.regprog); - vim_free(wp->w_match_head->pattern); - vim_free(wp->w_match_head); - wp->w_match_head = m; - } - redraw_win_later(wp, SOME_VALID); -} - -/* - * Get match from ID 'id' in window 'wp'. - * Return NULL if match not found. - */ - static matchitem_T * -get_match(win_T *wp, int id) -{ - matchitem_T *cur = wp->w_match_head; - - while (cur != NULL && cur->id != id) - cur = cur->next; - return cur; -} - -/* - * Init for calling prepare_search_hl(). - */ - void -init_search_hl(win_T *wp, match_T *search_hl) -{ - matchitem_T *cur; - - // Setup for match and 'hlsearch' highlighting. Disable any previous - // match - cur = wp->w_match_head; - while (cur != NULL) - { - cur->hl.rm = cur->match; - if (cur->hlg_id == 0) - cur->hl.attr = 0; - else - cur->hl.attr = syn_id2attr(cur->hlg_id); - cur->hl.buf = wp->w_buffer; - cur->hl.lnum = 0; - cur->hl.first_lnum = 0; -# ifdef FEAT_RELTIME - // Set the time limit to 'redrawtime'. - profile_setlimit(p_rdt, &(cur->hl.tm)); -# endif - cur = cur->next; - } - search_hl->buf = wp->w_buffer; - search_hl->lnum = 0; - search_hl->first_lnum = 0; - // time limit is set at the toplevel, for all windows -} - -/* - * If there is a match fill "shl" and return one. - * Return zero otherwise. - */ - static int -next_search_hl_pos( - match_T *shl, // points to a match - linenr_T lnum, - posmatch_T *posmatch, // match positions - colnr_T mincol) // minimal column for a match -{ - int i; - int found = -1; - - for (i = posmatch->cur; i < MAXPOSMATCH; i++) - { - llpos_T *pos = &posmatch->pos[i]; - - if (pos->lnum == 0) - break; - if (pos->len == 0 && pos->col < mincol) - continue; - if (pos->lnum == lnum) - { - if (found >= 0) - { - // if this match comes before the one at "found" then swap - // them - if (pos->col < posmatch->pos[found].col) - { - llpos_T tmp = *pos; - - *pos = posmatch->pos[found]; - posmatch->pos[found] = tmp; - } - } - else - found = i; - } - } - posmatch->cur = 0; - if (found >= 0) - { - colnr_T start = posmatch->pos[found].col == 0 - ? 0 : posmatch->pos[found].col - 1; - colnr_T end = posmatch->pos[found].col == 0 - ? MAXCOL : start + posmatch->pos[found].len; - - shl->lnum = lnum; - shl->rm.startpos[0].lnum = 0; - shl->rm.startpos[0].col = start; - shl->rm.endpos[0].lnum = 0; - shl->rm.endpos[0].col = end; - shl->is_addpos = TRUE; - posmatch->cur = found + 1; - return 1; - } - return 0; -} - -/* - * Search for a next 'hlsearch' or match. - * Uses shl->buf. - * Sets shl->lnum and shl->rm contents. - * Note: Assumes a previous match is always before "lnum", unless - * shl->lnum is zero. - * Careful: Any pointers for buffer lines will become invalid. - */ - static void -next_search_hl( - win_T *win, - match_T *search_hl, - match_T *shl, // points to search_hl or a match - linenr_T lnum, - colnr_T mincol, // minimal column for a match - matchitem_T *cur) // to retrieve match positions if any -{ - linenr_T l; - colnr_T matchcol; - long nmatched; - int called_emsg_before = called_emsg; - - // for :{range}s/pat only highlight inside the range - if (lnum < search_first_line || lnum > search_last_line) - { - shl->lnum = 0; - return; - } - - if (shl->lnum != 0) - { - // Check for three situations: - // 1. If the "lnum" is below a previous match, start a new search. - // 2. If the previous match includes "mincol", use it. - // 3. Continue after the previous match. - l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum; - if (lnum > l) - shl->lnum = 0; - else if (lnum < l || shl->rm.endpos[0].col > mincol) - return; - } - - /* - * Repeat searching for a match until one is found that includes "mincol" - * or none is found in this line. - */ - for (;;) - { -# ifdef FEAT_RELTIME - // Stop searching after passing the time limit. - if (profile_passed_limit(&(shl->tm))) - { - shl->lnum = 0; // no match found in time - break; - } -# endif - // Three situations: - // 1. No useful previous match: search from start of line. - // 2. Not Vi compatible or empty match: continue at next character. - // Break the loop if this is beyond the end of the line. - // 3. Vi compatible searching: continue at end of previous match. - if (shl->lnum == 0) - matchcol = 0; - else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL - || (shl->rm.endpos[0].lnum == 0 - && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) - { - char_u *ml; - - matchcol = shl->rm.startpos[0].col; - ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol; - if (*ml == NUL) - { - ++matchcol; - shl->lnum = 0; - break; - } - if (has_mbyte) - matchcol += mb_ptr2len(ml); - else - ++matchcol; - } - else - matchcol = shl->rm.endpos[0].col; - - shl->lnum = lnum; - if (shl->rm.regprog != NULL) - { - // Remember whether shl->rm is using a copy of the regprog in - // cur->match. - int regprog_is_copy = (shl != search_hl && cur != NULL - && shl == &cur->hl - && cur->match.regprog == cur->hl.rm.regprog); - int timed_out = FALSE; - - nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, - matchcol, -#ifdef FEAT_RELTIME - &(shl->tm), &timed_out -#else - NULL, NULL -#endif - ); - // Copy the regprog, in case it got freed and recompiled. - if (regprog_is_copy) - cur->match.regprog = cur->hl.rm.regprog; - - if (called_emsg > called_emsg_before || got_int || timed_out) - { - // Error while handling regexp: stop using this regexp. - if (shl == search_hl) - { - // don't free regprog in the match list, it's a copy - vim_regfree(shl->rm.regprog); - set_no_hlsearch(TRUE); - } - shl->rm.regprog = NULL; - shl->lnum = 0; - got_int = FALSE; // avoid the "Type :quit to exit Vim" message - break; - } - } - else if (cur != NULL) - nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); - else - nmatched = 0; - if (nmatched == 0) - { - shl->lnum = 0; // no match found - break; - } - if (shl->rm.startpos[0].lnum > 0 - || shl->rm.startpos[0].col >= mincol - || nmatched > 1 - || shl->rm.endpos[0].col > mincol) - { - shl->lnum += shl->rm.startpos[0].lnum; - break; // useful match found - } - } -} - -/* - * Advance to the match in window "wp" line "lnum" or past it. - */ - void -prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) -{ - matchitem_T *cur; // points to the match list - match_T *shl; // points to search_hl or a match - int shl_flag; // flag to indicate whether search_hl - // has been processed or not - int pos_inprogress; // marks that position match search is - // in progress - int n; - - // When using a multi-line pattern, start searching at the top - // of the window or just after a closed fold. - // Do this both for search_hl and the match list. - cur = wp->w_match_head; - shl_flag = WIN_IS_POPUP(wp); // skip search_hl in a popup window - while (cur != NULL || shl_flag == FALSE) - { - if (shl_flag == FALSE) - { - shl = search_hl; - shl_flag = TRUE; - } - else - shl = &cur->hl; - if (shl->rm.regprog != NULL - && shl->lnum == 0 - && re_multiline(shl->rm.regprog)) - { - if (shl->first_lnum == 0) - { -# ifdef FEAT_FOLDING - for (shl->first_lnum = lnum; - shl->first_lnum > wp->w_topline; --shl->first_lnum) - if (hasFoldingWin(wp, shl->first_lnum - 1, - NULL, NULL, TRUE, NULL)) - break; -# else - shl->first_lnum = wp->w_topline; -# endif - } - if (cur != NULL) - cur->pos.cur = 0; - pos_inprogress = TRUE; - n = 0; - while (shl->first_lnum < lnum && (shl->rm.regprog != NULL - || (cur != NULL && pos_inprogress))) - { - next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n, - shl == search_hl ? NULL : cur); - pos_inprogress = cur == NULL || cur->pos.cur == 0 - ? FALSE : TRUE; - if (shl->lnum != 0) - { - shl->first_lnum = shl->lnum - + shl->rm.endpos[0].lnum - - shl->rm.startpos[0].lnum; - n = shl->rm.endpos[0].col; - } - else - { - ++shl->first_lnum; - n = 0; - } - } - } - if (shl != search_hl && cur != NULL) - cur = cur->next; - } -} - -/* - * Prepare for 'hlsearch' and match highlighting in one window line. - * Return TRUE if there is such highlighting and set "search_attr" to the - * current highlight attribute. - */ - int -prepare_search_hl_line( - win_T *wp, - linenr_T lnum, - colnr_T mincol, - char_u **line, - match_T *search_hl, - int *search_attr) -{ - matchitem_T *cur; // points to the match list - match_T *shl; // points to search_hl or a match - int shl_flag; // flag to indicate whether search_hl - // has been processed or not - int area_highlighting = FALSE; - - /* - * Handle highlighting the last used search pattern and matches. - * Do this for both search_hl and the match list. - * Do not use search_hl in a popup window. - */ - cur = wp->w_match_head; - shl_flag = WIN_IS_POPUP(wp); - while (cur != NULL || shl_flag == FALSE) - { - if (shl_flag == FALSE) - { - shl = search_hl; - shl_flag = TRUE; - } - else - shl = &cur->hl; - shl->startcol = MAXCOL; - shl->endcol = MAXCOL; - shl->attr_cur = 0; - shl->is_addpos = FALSE; - if (cur != NULL) - cur->pos.cur = 0; - next_search_hl(wp, search_hl, shl, lnum, mincol, - shl == search_hl ? NULL : cur); - - // Need to get the line again, a multi-line regexp may have made it - // invalid. - *line = ml_get_buf(wp->w_buffer, lnum, FALSE); - - if (shl->lnum != 0 && shl->lnum <= lnum) - { - if (shl->lnum == lnum) - shl->startcol = shl->rm.startpos[0].col; - else - shl->startcol = 0; - if (lnum == shl->lnum + shl->rm.endpos[0].lnum - - shl->rm.startpos[0].lnum) - shl->endcol = shl->rm.endpos[0].col; - else - shl->endcol = MAXCOL; - // Highlight one character for an empty match. - if (shl->startcol == shl->endcol) - { - if (has_mbyte && (*line)[shl->endcol] != NUL) - shl->endcol += (*mb_ptr2len)((*line) + shl->endcol); - else - ++shl->endcol; - } - if ((long)shl->startcol < mincol) // match at leftcol - { - shl->attr_cur = shl->attr; - *search_attr = shl->attr; - } - area_highlighting = TRUE; - } - if (shl != search_hl && cur != NULL) - cur = cur->next; - } - return area_highlighting; -} - -/* - * For a position in a line: Check for start/end of 'hlsearch' and other - * matches. - * After end, check for start/end of next match. - * When another match, have to check for start again. - * Watch out for matching an empty string! - * Return the updated search_attr. - */ - int -update_search_hl( - win_T *wp, - linenr_T lnum, - colnr_T col, - char_u **line, - match_T *search_hl, - int *has_match_conc UNUSED, - int *match_conc UNUSED, - int did_line_attr, - int lcs_eol_one) -{ - matchitem_T *cur; // points to the match list - match_T *shl; // points to search_hl or a match - int shl_flag; // flag to indicate whether search_hl - // has been processed or not - int pos_inprogress; // marks that position match search is in - // progress - int search_attr = 0; - - - // Do this for 'search_hl' and the match list (ordered by priority). - cur = wp->w_match_head; - shl_flag = WIN_IS_POPUP(wp); - while (cur != NULL || shl_flag == FALSE) - { - if (shl_flag == FALSE - && ((cur != NULL - && cur->priority > SEARCH_HL_PRIORITY) - || cur == NULL)) - { - shl = search_hl; - shl_flag = TRUE; - } - else - shl = &cur->hl; - if (cur != NULL) - cur->pos.cur = 0; - pos_inprogress = TRUE; - while (shl->rm.regprog != NULL || (cur != NULL && pos_inprogress)) - { - if (shl->startcol != MAXCOL - && col >= shl->startcol - && col < shl->endcol) - { - int next_col = col + mb_ptr2len(*line + col); - - if (shl->endcol < next_col) - shl->endcol = next_col; - shl->attr_cur = shl->attr; -# ifdef FEAT_CONCEAL - // Match with the "Conceal" group results in hiding - // the match. - if (cur != NULL - && shl != search_hl - && syn_name2id((char_u *)"Conceal") == cur->hlg_id) - { - *has_match_conc = col == shl->startcol ? 2 : 1; - *match_conc = cur->conceal_char; - } - else - *has_match_conc = *match_conc = 0; -# endif - } - else if (col == shl->endcol) - { - shl->attr_cur = 0; - next_search_hl(wp, search_hl, shl, lnum, col, - shl == search_hl ? NULL : cur); - pos_inprogress = !(cur == NULL || cur->pos.cur == 0); - - // Need to get the line again, a multi-line regexp may have - // made it invalid. - *line = ml_get_buf(wp->w_buffer, lnum, FALSE); - - if (shl->lnum == lnum) - { - shl->startcol = shl->rm.startpos[0].col; - if (shl->rm.endpos[0].lnum == 0) - shl->endcol = shl->rm.endpos[0].col; - else - shl->endcol = MAXCOL; - - if (shl->startcol == shl->endcol) - { - // highlight empty match, try again after - // it - if (has_mbyte) - shl->endcol += (*mb_ptr2len)(*line + shl->endcol); - else - ++shl->endcol; - } - - // Loop to check if the match starts at the - // current position - continue; - } - } - break; - } - if (shl != search_hl && cur != NULL) - cur = cur->next; - } - - // Use attributes from match with highest priority among 'search_hl' and - // the match list. - cur = wp->w_match_head; - shl_flag = WIN_IS_POPUP(wp); - while (cur != NULL || shl_flag == FALSE) - { - if (shl_flag == FALSE - && ((cur != NULL - && cur->priority > SEARCH_HL_PRIORITY) - || cur == NULL)) - { - shl = search_hl; - shl_flag = TRUE; - } - else - shl = &cur->hl; - if (shl->attr_cur != 0) - search_attr = shl->attr_cur; - if (shl != search_hl && cur != NULL) - cur = cur->next; - } - // Only highlight one character after the last column. - if (*(*line + col) == NUL && (did_line_attr >= 1 - || (wp->w_p_list && lcs_eol_one == -1))) - search_attr = 0; - return search_attr; -} - - int -get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol) -{ - long prevcol = curcol; - int prevcol_hl_flag = FALSE; - matchitem_T *cur; // points to the match list - - // we're not really at that column when skipping some text - if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) - ++prevcol; - - if (!search_hl->is_addpos && prevcol == (long)search_hl->startcol) - prevcol_hl_flag = TRUE; - else - { - cur = wp->w_match_head; - while (cur != NULL) - { - if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol) - { - prevcol_hl_flag = TRUE; - break; - } - cur = cur->next; - } - } - return prevcol_hl_flag; -} - -/* - * Get highlighting for the char after the text in "char_attr" from 'hlsearch' - * or match highlighting. - */ - void -get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr) -{ - matchitem_T *cur; // points to the match list - match_T *shl; // points to search_hl or a match - int shl_flag; // flag to indicate whether search_hl - // has been processed or not - - cur = wp->w_match_head; - shl_flag = WIN_IS_POPUP(wp); - while (cur != NULL || shl_flag == FALSE) - { - if (shl_flag == FALSE - && ((cur != NULL - && cur->priority > SEARCH_HL_PRIORITY) - || cur == NULL)) - { - shl = search_hl; - shl_flag = TRUE; - } - else - shl = &cur->hl; - if (col - 1 == (long)shl->startcol - && (shl == search_hl || !shl->is_addpos)) - *char_attr = shl->attr; - if (shl != search_hl && cur != NULL) - cur = cur->next; - } -} - -#endif // FEAT_SEARCH_EXTRA - -#if defined(FEAT_EVAL) || defined(PROTO) -# ifdef FEAT_SEARCH_EXTRA - static int -matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win) -{ - dictitem_T *di; - - if (tv->v_type != VAR_DICT) - { - emsg(_(e_dictreq)); - return FAIL; - } - - if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL) - *conceal_char = dict_get_string(tv->vval.v_dict, - (char_u *)"conceal", FALSE); - - if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL) - { - *win = find_win_by_nr_or_id(&di->di_tv); - if (*win == NULL) - { - emsg(_(e_invalwindow)); - return FAIL; - } - } - - return OK; -} -#endif - -/* - * "clearmatches()" function - */ - void -f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - win_T *win = get_optional_window(argvars, 0); - - if (win != NULL) - clear_matches(win); -#endif -} - -/* - * "getmatches()" function - */ - void -f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -# ifdef FEAT_SEARCH_EXTRA - dict_T *dict; - matchitem_T *cur; - int i; - win_T *win = get_optional_window(argvars, 0); - - if (rettv_list_alloc(rettv) == FAIL || win == NULL) - return; - - cur = win->w_match_head; - while (cur != NULL) - { - dict = dict_alloc(); - if (dict == NULL) - return; - if (cur->match.regprog == NULL) - { - // match added with matchaddpos() - for (i = 0; i < MAXPOSMATCH; ++i) - { - llpos_T *llpos; - char buf[30]; // use 30 to avoid compiler warning - list_T *l; - - llpos = &cur->pos.pos[i]; - if (llpos->lnum == 0) - break; - l = list_alloc(); - if (l == NULL) - break; - list_append_number(l, (varnumber_T)llpos->lnum); - if (llpos->col > 0) - { - list_append_number(l, (varnumber_T)llpos->col); - list_append_number(l, (varnumber_T)llpos->len); - } - sprintf(buf, "pos%d", i + 1); - dict_add_list(dict, buf, l); - } - } - else - { - dict_add_string(dict, "pattern", cur->pattern); - } - dict_add_string(dict, "group", syn_id2name(cur->hlg_id)); - dict_add_number(dict, "priority", (long)cur->priority); - dict_add_number(dict, "id", (long)cur->id); -# if defined(FEAT_CONCEAL) - if (cur->conceal_char) - { - char_u buf[MB_MAXBYTES + 1]; - - buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; - dict_add_string(dict, "conceal", (char_u *)&buf); - } -# endif - list_append_dict(rettv->vval.v_list, dict); - cur = cur->next; - } -# endif -} - -/* - * "setmatches()" function - */ - void -f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_SEARCH_EXTRA - list_T *l; - listitem_T *li; - dict_T *d; - list_T *s = NULL; - win_T *win = get_optional_window(argvars, 1); - - rettv->vval.v_number = -1; - if (argvars[0].v_type != VAR_LIST) - { - emsg(_(e_listreq)); - return; - } - if (win == NULL) - return; - - if ((l = argvars[0].vval.v_list) != NULL) - { - // To some extent make sure that we are dealing with a list from - // "getmatches()". - li = l->lv_first; - while (li != NULL) - { - if (li->li_tv.v_type != VAR_DICT - || (d = li->li_tv.vval.v_dict) == NULL) - { - emsg(_(e_invarg)); - return; - } - if (!(dict_find(d, (char_u *)"group", -1) != NULL - && (dict_find(d, (char_u *)"pattern", -1) != NULL - || dict_find(d, (char_u *)"pos1", -1) != NULL) - && dict_find(d, (char_u *)"priority", -1) != NULL - && dict_find(d, (char_u *)"id", -1) != NULL)) - { - emsg(_(e_invarg)); - return; - } - li = li->li_next; - } - - clear_matches(win); - li = l->lv_first; - while (li != NULL) - { - int i = 0; - char buf[30]; // use 30 to avoid compiler warning - dictitem_T *di; - char_u *group; - int priority; - int id; - char_u *conceal; - - d = li->li_tv.vval.v_dict; - if (dict_find(d, (char_u *)"pattern", -1) == NULL) - { - if (s == NULL) - { - s = list_alloc(); - if (s == NULL) - return; - } - - // match from matchaddpos() - for (i = 1; i < 9; i++) - { - sprintf((char *)buf, (char *)"pos%d", i); - if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) - { - if (di->di_tv.v_type != VAR_LIST) - return; - - list_append_tv(s, &di->di_tv); - s->lv_refcount++; - } - else - break; - } - } - - group = dict_get_string(d, (char_u *)"group", TRUE); - priority = (int)dict_get_number(d, (char_u *)"priority"); - id = (int)dict_get_number(d, (char_u *)"id"); - conceal = dict_find(d, (char_u *)"conceal", -1) != NULL - ? dict_get_string(d, (char_u *)"conceal", TRUE) - : NULL; - if (i == 0) - { - match_add(win, group, - dict_get_string(d, (char_u *)"pattern", FALSE), - priority, id, NULL, conceal); - } - else - { - match_add(win, group, NULL, priority, id, s, conceal); - list_unref(s); - s = NULL; - } - vim_free(group); - vim_free(conceal); - - li = li->li_next; - } - rettv->vval.v_number = 0; - } -#endif -} - -/* - * "matchadd()" function - */ - void -f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -# ifdef FEAT_SEARCH_EXTRA - char_u buf[NUMBUFLEN]; - char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); // group - char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); // pattern - int prio = 10; // default priority - int id = -1; - int error = FALSE; - char_u *conceal_char = NULL; - win_T *win = curwin; - - rettv->vval.v_number = -1; - - if (grp == NULL || pat == NULL) - return; - if (argvars[2].v_type != VAR_UNKNOWN) - { - prio = (int)tv_get_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) - { - id = (int)tv_get_number_chk(&argvars[3], &error); - if (argvars[4].v_type != VAR_UNKNOWN - && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) - return; - } - } - if (error == TRUE) - return; - if (id >= 1 && id <= 3) - { - semsg(_("E798: ID is reserved for \":match\": %d"), id); - return; - } - - rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL, - conceal_char); -# endif -} - -/* - * "matchaddpos()" function - */ - void -f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -# ifdef FEAT_SEARCH_EXTRA - char_u buf[NUMBUFLEN]; - char_u *group; - int prio = 10; - int id = -1; - int error = FALSE; - list_T *l; - char_u *conceal_char = NULL; - win_T *win = curwin; - - rettv->vval.v_number = -1; - - group = tv_get_string_buf_chk(&argvars[0], buf); - if (group == NULL) - return; - - if (argvars[1].v_type != VAR_LIST) - { - semsg(_(e_listarg), "matchaddpos()"); - return; - } - l = argvars[1].vval.v_list; - if (l == NULL) - return; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - prio = (int)tv_get_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) - { - id = (int)tv_get_number_chk(&argvars[3], &error); - - if (argvars[4].v_type != VAR_UNKNOWN - && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) - return; - } - } - if (error == TRUE) - return; - - // id == 3 is ok because matchaddpos() is supposed to substitute :3match - if (id == 1 || id == 2) - { - semsg(_("E798: ID is reserved for \":match\": %d"), id); - return; - } - - rettv->vval.v_number = match_add(win, group, NULL, prio, id, l, - conceal_char); -# endif -} - -/* - * "matcharg()" function - */ - void -f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) -{ - if (rettv_list_alloc(rettv) == OK) - { -# ifdef FEAT_SEARCH_EXTRA - int id = (int)tv_get_number(&argvars[0]); - matchitem_T *m; - - if (id >= 1 && id <= 3) - { - if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) - { - list_append_string(rettv->vval.v_list, - syn_id2name(m->hlg_id), -1); - list_append_string(rettv->vval.v_list, m->pattern, -1); - } - else - { - list_append_string(rettv->vval.v_list, NULL, -1); - list_append_string(rettv->vval.v_list, NULL, -1); - } - } -# endif - } -} - -/* - * "matchdelete()" function - */ - void -f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -# ifdef FEAT_SEARCH_EXTRA - win_T *win = get_optional_window(argvars, 1); - - if (win == NULL) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = match_delete(win, - (int)tv_get_number(&argvars[0]), TRUE); -# endif -} -#endif - -#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) -/* - * ":[N]match {group} {pattern}" - * Sets nextcmd to the start of the next command, if any. Also called when - * skipping commands to find the next command. - */ - void -ex_match(exarg_T *eap) -{ - char_u *p; - char_u *g = NULL; - char_u *end; - int c; - int id; - - if (eap->line2 <= 3) - id = eap->line2; - else - { - emsg(_(e_invcmd)); - return; - } - - // First clear any old pattern. - if (!eap->skip) - match_delete(curwin, id, FALSE); - - if (ends_excmd2(eap->cmd, eap->arg)) - end = eap->arg; - else if ((STRNICMP(eap->arg, "none", 4) == 0 - && (VIM_ISWHITE(eap->arg[4]) - || ends_excmd2(eap->arg, eap->arg + 4)))) - end = eap->arg + 4; - else - { - p = skiptowhite(eap->arg); - if (!eap->skip) - g = vim_strnsave(eap->arg, p - eap->arg); - p = skipwhite(p); - if (*p == NUL) - { - // There must be two arguments. - vim_free(g); - semsg(_(e_invarg2), eap->arg); - return; - } - end = skip_regexp(p + 1, *p, TRUE); - if (!eap->skip) - { - if (*end != NUL && !ends_excmd2(end, skipwhite(end + 1))) - { - vim_free(g); - eap->errmsg = e_trailing; - return; - } - if (*end != *p) - { - vim_free(g); - semsg(_(e_invarg2), p); - return; - } - - c = *end; - *end = NUL; - match_add(curwin, g, p + 1, 10, id, NULL, NULL); - vim_free(g); - *end = c; - } - } - eap->nextcmd = find_nextcmd(end); -} -#endif diff --git a/src/if_lua.c b/src/if_lua.c index 75231b4c27..9852c618e8 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -35,6 +35,13 @@ typedef struct { } luaV_Funcref; typedef void (*msgfunc_T)(char_u *); +typedef struct { + int lua_funcref; // ref to a lua func + int lua_tableref; // ref to a lua table if metatable else LUA_NOREF. used + // for __call + lua_State *L; +} luaV_CFuncState; + static const char LUAVIM_DICT[] = "dict"; static const char LUAVIM_LIST[] = "list"; static const char LUAVIM_BLOB[] = "blob"; @@ -45,6 +52,8 @@ static const char LUAVIM_FREE[] = "luaV_free"; static const char LUAVIM_LUAEVAL[] = "luaV_luaeval"; static const char LUAVIM_SETREF[] = "luaV_setref"; +static const char LUA___CALL[] = "__call"; + // most functions are closures with a cache table as first upvalue; // get/setudata manage references to vim userdata in cache table through // object pointers (light userdata) @@ -64,7 +73,7 @@ static const char LUAVIM_SETREF[] = "luaV_setref"; #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg) #define luaV_checktypval(L, a, v, msg) \ do { \ - if (luaV_totypval(L, a, v) == FAIL) \ + if (luaV_totypval(L, a, v) == FAIL) \ luaL_error(L, msg ": cannot convert value"); \ } while (0) @@ -72,6 +81,8 @@ static luaV_List *luaV_pushlist(lua_State *L, list_T *lis); static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic); static luaV_Blob *luaV_pushblob(lua_State *L, blob_T *blo); static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name); +static int luaV_call_lua_func(int argcount, typval_T *argvars, typval_T *rettv, void *state); +static void luaV_call_lua_func_free(void *state); #if LUA_VERSION_NUM <= 501 #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n) @@ -120,6 +131,8 @@ static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name); #define luaL_addlstring dll_luaL_addlstring #define luaL_pushresult dll_luaL_pushresult #define luaL_loadstring dll_luaL_loadstring +#define luaL_ref dll_luaL_ref +#define luaL_unref dll_luaL_unref // lua #if LUA_VERSION_NUM <= 501 #define lua_tonumber dll_lua_tonumber @@ -215,6 +228,12 @@ void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B); void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); void (*dll_luaL_pushresult) (luaL_Buffer *B); int (*dll_luaL_loadstring) (lua_State *L, const char *s); +int (*dll_luaL_ref) (lua_State *L, int idx); +#if LUA_VERSION_NUM <= 502 +void (*dll_luaL_unref) (lua_State *L, int idx, int n); +#else +void (*dll_luaL_unref) (lua_State *L, int idx, lua_Integer n); +#endif // lua #if LUA_VERSION_NUM <= 501 lua_Number (*dll_lua_tonumber) (lua_State *L, int idx); @@ -328,6 +347,8 @@ static const luaV_Reg luaV_dll[] = { {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring}, {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult}, {"luaL_loadstring", (luaV_function) &dll_luaL_loadstring}, + {"luaL_ref", (luaV_function) &dll_luaL_ref}, + {"luaL_unref", (luaV_function) &dll_luaL_unref}, // lua #if LUA_VERSION_NUM <= 501 {"lua_tonumber", (luaV_function) &dll_lua_tonumber}, @@ -555,6 +576,8 @@ luaV_totypval(lua_State *L, int pos, typval_T *tv) { int status = OK; + tv->v_lock = 0; + switch (lua_type(L, pos)) { case LUA_TBOOLEAN: @@ -591,6 +614,45 @@ luaV_totypval(lua_State *L, int pos, typval_T *tv) tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos); #endif break; + case LUA_TFUNCTION: + { + char_u *name; + lua_pushvalue(L, pos); + luaV_CFuncState *state = ALLOC_CLEAR_ONE(luaV_CFuncState); + state->lua_funcref = luaL_ref(L, LUA_REGISTRYINDEX); + state->L = L; + state->lua_tableref = LUA_NOREF; + name = register_cfunc(&luaV_call_lua_func, + &luaV_call_lua_func_free, state); + tv->v_type = VAR_FUNC; + tv->vval.v_string = vim_strsave(name); + break; + } + case LUA_TTABLE: + { + lua_pushvalue(L, pos); + int lua_tableref = luaL_ref(L, LUA_REGISTRYINDEX); + if (lua_getmetatable(L, pos)) { + lua_getfield(L, -1, LUA___CALL); + if (lua_isfunction(L, -1)) { + char_u *name; + int lua_funcref = luaL_ref(L, LUA_REGISTRYINDEX); + luaV_CFuncState *state = ALLOC_CLEAR_ONE(luaV_CFuncState); + state->lua_funcref = lua_funcref; + state->L = L; + state->lua_tableref = lua_tableref; + name = register_cfunc(&luaV_call_lua_func, + &luaV_call_lua_func_free, state); + tv->v_type = VAR_FUNC; + tv->vval.v_string = vim_strsave(name); + break; + } + } + tv->v_type = VAR_NUMBER; + tv->vval.v_number = 0; + status = FAIL; + break; + } case LUA_TUSERDATA: { void *p = lua_touserdata(L, pos); @@ -811,7 +873,13 @@ luaV_list_index(lua_State *L) list_T *l = luaV_unbox(L, luaV_List, 1); if (lua_isnumber(L, 2)) // list item? { - listitem_T *li = list_find(l, (long) luaL_checkinteger(L, 2)); + long n = (long) luaL_checkinteger(L, 2); + listitem_T *li; + + // Lua array index starts with 1 while Vim uses 0, subtract 1 to + // normalize. + n -= 1; + li = list_find(l, n); if (li == NULL) lua_pushnil(L); else @@ -840,22 +908,38 @@ luaV_list_newindex(lua_State *L) list_T *l = luaV_unbox(L, luaV_List, 1); long n = (long) luaL_checkinteger(L, 2); listitem_T *li; + + // Lua array index starts with 1 while Vim uses 0, subtract 1 to normalize. + n -= 1; + if (l->lv_lock) luaL_error(L, "list is locked"); li = list_find(l, n); - if (li == NULL) return 0; - if (lua_isnil(L, 3)) // remove? + if (li == NULL) { - vimlist_remove(l, li, li); - listitem_free(l, li); + if (!lua_isnil(L, 3)) + { + typval_T v; + luaV_checktypval(L, 3, &v, "inserting list item"); + if (list_insert_tv(l, &v, li) == FAIL) + luaL_error(L, "failed to add item to list"); + clear_tv(&v); + } } else { - typval_T v; - luaV_checktypval(L, 3, &v, "setting list item"); - clear_tv(&li->li_tv); - copy_tv(&v, &li->li_tv); - clear_tv(&v); + if (lua_isnil(L, 3)) // remove? + { + vimlist_remove(l, li, li); + listitem_free(l, li); + } + else + { + typval_T v; + luaV_checktypval(L, 3, &v, "setting list item"); + clear_tv(&li->li_tv); + li->li_tv = v; + } } return 0; } @@ -1001,7 +1085,7 @@ luaV_dict_newindex(lua_State *L) dict_T *d = luaV_unbox(L, luaV_Dict, 1); char_u *key = (char_u *) luaL_checkstring(L, 2); dictitem_T *di; - typval_T v; + typval_T tv; if (d->dv_lock) luaL_error(L, "dict is locked"); @@ -1011,9 +1095,12 @@ luaV_dict_newindex(lua_State *L) luaL_error(L, "empty key"); if (!lua_isnil(L, 3)) // read value? { - luaV_checktypval(L, 3, &v, "setting dict item"); - if (d->dv_scope == VAR_DEF_SCOPE && v.v_type == VAR_FUNC) + luaV_checktypval(L, 3, &tv, "setting dict item"); + if (d->dv_scope == VAR_DEF_SCOPE && tv.v_type == VAR_FUNC) + { + clear_tv(&tv); luaL_error(L, "cannot assign funcref to builtin scope"); + } } di = dict_find(d, key, -1); if (di == NULL) // non-existing key? @@ -1022,10 +1109,14 @@ luaV_dict_newindex(lua_State *L) return 0; di = dictitem_alloc(key); if (di == NULL) + { + clear_tv(&tv); return 0; + } if (dict_add(d, di) == FAIL) { vim_free(di); + clear_tv(&tv); return 0; } } @@ -1038,10 +1129,7 @@ luaV_dict_newindex(lua_State *L) dictitem_free(di); } else - { - copy_tv(&v, &di->di_tv); - clear_tv(&v); - } + di->di_tv = tv; return 0; } @@ -1358,7 +1446,8 @@ luaV_buffer_newindex(lua_State *L) curwin->w_cursor.lnum -= 1; check_cursor_col(); } - else check_cursor(); + else + check_cursor(); changed_cline_bef_curs(); } invalidate_botline(); @@ -1759,8 +1848,7 @@ luaV_dict(lua_State *L) lua_pushnil(L); return 1; } - copy_tv(&v, &di->di_tv); - clear_tv(&v); + di->di_tv = v; lua_pop(L, 2); // key copy and value } } @@ -2315,7 +2403,7 @@ ex_luado(exarg_T *eap) lua_replace(L, -2); // function -> body for (l = eap->line1; l <= eap->line2; l++) { - // Check the line number, the command my have deleted lines. + // Check the line number, the command may have deleted lines. if (l > curbuf->b_ml.ml_line_count) break; @@ -2415,4 +2503,53 @@ update_package_paths_in_lua() } } +/* + * Native C function callback + */ + static int +luaV_call_lua_func( + int argcount, + typval_T *argvars, + typval_T *rettv, + void *state) +{ + int i; + int luaargcount = argcount; + luaV_CFuncState *funcstate = (luaV_CFuncState*)state; + lua_rawgeti(funcstate->L, LUA_REGISTRYINDEX, funcstate->lua_funcref); + + if (funcstate->lua_tableref != LUA_NOREF) + { + // First arg for metatable __call method is a table + luaargcount += 1; + lua_rawgeti(funcstate->L, LUA_REGISTRYINDEX, funcstate->lua_tableref); + } + + for (i = 0; i < argcount; ++i) + luaV_pushtypval(funcstate->L, &argvars[i]); + + if (lua_pcall(funcstate->L, luaargcount, 1, 0)) + { + luaV_emsg(funcstate->L); + return FCERR_OTHER; + } + + luaV_checktypval(funcstate->L, -1, rettv, "get return value"); + return FCERR_NONE; +} + +/* + * Free up any lua references held by the func state. + */ + static void +luaV_call_lua_func_free(void *state) +{ + luaV_CFuncState *funcstate = (luaV_CFuncState*)state; + luaL_unref(L, LUA_REGISTRYINDEX, funcstate->lua_funcref); + funcstate->L = NULL; + if (funcstate->lua_tableref != LUA_NOREF) + luaL_unref(L, LUA_REGISTRYINDEX, funcstate->lua_tableref); + VIM_CLEAR(funcstate); +} + #endif diff --git a/src/if_ole.cpp b/src/if_ole.cpp index 34ce232660..e415a1924d 100644 --- a/src/if_ole.cpp +++ b/src/if_ole.cpp @@ -388,7 +388,7 @@ CVim::Eval(BSTR expr, BSTR *result) /* Evaluate the expression */ ++emsg_skip; - str = (char *)eval_to_string((char_u *)buffer, NULL, TRUE); + str = (char *)eval_to_string((char_u *)buffer, TRUE); --emsg_skip; vim_free(buffer); if (str == NULL) diff --git a/src/if_perl.xs b/src/if_perl.xs index bf269cbcb0..cad571c5c7 100644 --- a/src/if_perl.xs +++ b/src/if_perl.xs @@ -832,7 +832,6 @@ msg_split( char_u * eval_to_string( char_u *arg UNUSED, - char_u **nextcmd UNUSED, int dolist UNUSED) { return NULL; @@ -1562,7 +1561,7 @@ Eval(str) PREINIT: char_u *value; PPCODE: - value = eval_to_string((char_u *)str, (char_u **)0, TRUE); + value = eval_to_string((char_u *)str, TRUE); if (value == NULL) { XPUSHs(sv_2mortal(newSViv(0))); diff --git a/src/if_py_both.h b/src/if_py_both.h index e262d1f75f..c7df93be2a 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -1913,7 +1913,6 @@ DictionaryAssItem( if (dict_add(dict, di) == FAIL) { - vim_free(di); dictitem_free(di); RAISE_KEY_ADD_FAIL(key); Py_XDECREF(todecref); @@ -2251,6 +2250,9 @@ ListNew(PyTypeObject *subtype, list_T *list) { ListObject *self; + if (list == NULL) + return NULL; + self = (ListObject *) subtype->tp_alloc(subtype, 0); if (self == NULL) return NULL; @@ -2696,6 +2698,12 @@ ListAssIndex(ListObject *self, Py_ssize_t index, PyObject *obj) if (obj == NULL) { li = list_find(l, (long) index); + if (li == NULL) + { + PyErr_VIM_FORMAT(N_("internal error: failed to get Vim " + "list item %d"), (int) index); + return -1; + } vimlist_remove(l, li, li); clear_tv(&li->li_tv); vim_free(li); @@ -2717,6 +2725,12 @@ ListAssIndex(ListObject *self, Py_ssize_t index, PyObject *obj) else { li = list_find(l, (long) index); + if (li == NULL) + { + PyErr_VIM_FORMAT(N_("internal error: failed to get Vim " + "list item %d"), (int) index); + return -1; + } clear_tv(&li->li_tv); copy_tv(&tv, &li->li_tv); clear_tv(&tv); @@ -3898,7 +3912,7 @@ WindowDestructor(WindowObject *self) PyObject_GC_UnTrack((void *)(self)); if (self->win && self->win != INVALID_WINDOW_VALUE) WIN_PYTHON_REF(self->win) = NULL; - Py_XDECREF(((PyObject *)(self->tabObject))); + Py_XDECREF(((PyObject *)(self->tabObject))); PyObject_GC_Del((void *)(self)); } diff --git a/src/if_python3.c b/src/if_python3.c index ecca163b09..d540226b32 100644 --- a/src/if_python3.c +++ b/src/if_python3.c @@ -1256,6 +1256,10 @@ BufferAsSubscript(PyObject *self, PyObject* idx, PyObject* val) if (PyLong_Check(idx)) { long n = PyLong_AsLong(idx); + + if (CheckBuffer((BufferObject *) self)) + return -1; + return RBAsItem((BufferObject *)(self), n, val, 1, (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count, NULL); diff --git a/src/if_tcl.c b/src/if_tcl.c index c274b26750..2775221f46 100644 --- a/src/if_tcl.c +++ b/src/if_tcl.c @@ -1373,7 +1373,7 @@ tclvimexpr( #ifdef FEAT_EVAL expr = Tcl_GetStringFromObj(objv[objn], NULL); - str = (char *)eval_to_string((char_u *)expr, NULL, TRUE); + str = (char *)eval_to_string((char_u *)expr, TRUE); if (str == NULL) Tcl_SetResult(interp, _("invalid expression"), TCL_STATIC); else diff --git a/src/indent.c b/src/indent.c index a1d4d3628e..d786f26f26 100644 --- a/src/indent.c +++ b/src/indent.c @@ -757,6 +757,10 @@ set_indent( // Replace the line (unless undo fails). if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK) { + colnr_T old_offset = (colnr_T)(p - oldline); + colnr_T new_offset = (colnr_T)(s - newline); + + // this may free "newline" ml_replace(curwin->w_cursor.lnum, newline, FALSE); if (flags & SIN_CHANGED) changed_bytes(curwin->w_cursor.lnum, 0); @@ -764,24 +768,24 @@ set_indent( // Correct saved cursor position if it is in this line. if (saved_cursor.lnum == curwin->w_cursor.lnum) { - if (saved_cursor.col >= (colnr_T)(p - oldline)) + if (saved_cursor.col >= old_offset) // cursor was after the indent, adjust for the number of // bytes added/removed - saved_cursor.col += ind_len - (colnr_T)(p - oldline); - else if (saved_cursor.col >= (colnr_T)(s - newline)) + saved_cursor.col += ind_len - old_offset; + else if (saved_cursor.col >= new_offset) // cursor was in the indent, and is now after it, put it back // at the start of the indent (replacing spaces with TAB) - saved_cursor.col = (colnr_T)(s - newline); + saved_cursor.col = new_offset; } #ifdef FEAT_PROP_POPUP { - int added = ind_len - (colnr_T)(p - oldline); + int added = ind_len - old_offset; // When increasing indent this behaves like spaces were inserted at // the old indent, when decreasing indent it behaves like spaces // were deleted at the new indent. adjust_prop_columns(curwin->w_cursor.lnum, - (colnr_T)(added > 0 ? (p - oldline) : ind_len), added, 0); + added > 0 ? old_offset : (colnr_T)ind_len, added, 0); } #endif retval = TRUE; diff --git a/src/libvterm/src/mouse.c b/src/libvterm/src/mouse.c index 4e363134eb..ed60b0147d 100644 --- a/src/libvterm/src/mouse.c +++ b/src/libvterm/src/mouse.c @@ -83,7 +83,7 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod) state->mouse_buttons &= ~(1 << (button-1)); } - /* Most of the time we don't get button releases from 4/5 */ + /* Most of the time we don't get button releases from 4/5/6/7 */ if(state->mouse_buttons == old_buttons && button < 4) return; if (!(state->mouse_flags & MOUSE_WANT_CLICK)) @@ -92,7 +92,7 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod) if(button < 4) { output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row); } - else if(button < 6) { + else if(button < 8) { output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row); } } diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c index 173f64f682..c5a0b71c5d 100644 --- a/src/libvterm/src/pen.c +++ b/src/libvterm/src/pen.c @@ -106,8 +106,7 @@ static int lookup_colour(const VTermState *state, int palette, const long args[] } lookup_colour_palette(state, args[0], col); - - return argcount ? 1 : 0; + return 1; default: DEBUG_LOG1("Unrecognised colour palette %d\n", palette); diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 30438efe82..4fe3d7d20b 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -1844,14 +1844,14 @@ static int on_resize(int rows, int cols, void *user) state->pos.col++; } - if(state->pos.row >= rows) - state->pos.row = rows - 1; if(state->pos.row < 0) state->pos.row = 0; - if(state->pos.col >= cols) - state->pos.col = cols - 1; + if(state->pos.row >= rows) + state->pos.row = rows - 1; if(state->pos.col < 0) state->pos.col = 0; + if(state->pos.col >= cols) + state->pos.col = cols - 1; updatecursor(state, &oldpos, 1); diff --git a/src/libvterm/t/63screen_resize.test b/src/libvterm/t/63screen_resize.test index 87932f66d4..87b88d64e0 100644 --- a/src/libvterm/t/63screen_resize.test +++ b/src/libvterm/t/63screen_resize.test @@ -69,6 +69,22 @@ RESIZE 24,80 ?screen_chars 22,0,23,10 = "Line 25" ?cursor = 23,0 +!Resize shorter does not send the cursor to a negative row +# See also https://github.com/vim/vim/pull/6141 +RESET +WANTSCREEN -b +RESIZE 25,80 +WANTSCREEN b +PUSH "\e[24HLine 24\r\nLine 25\e[H" + ?cursor = 0,0 +RESIZE 20,80 + sb_pushline 80 = + sb_pushline 80 = + sb_pushline 80 = + sb_pushline 80 = + sb_pushline 80 = + ?cursor = 0,0 + !Resize taller attempts to pop scrollback RESET WANTSCREEN -b diff --git a/src/list.c b/src/list.c index 130ab25251..e8d5f5f546 100644 --- a/src/list.c +++ b/src/list.c @@ -1156,15 +1156,19 @@ f_join(typval_T *argvars, typval_T *rettv) /* * Allocate a variable for a List and fill it from "*arg". + * "*arg" points to the "[". * Return OK or FAIL. */ int -get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error) +eval_list(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error) { - int evaluate = flags & EVAL_EVALUATE; + int evaluate = evalarg == NULL ? FALSE + : evalarg->eval_flags & EVAL_EVALUATE; list_T *l = NULL; typval_T tv; listitem_T *item; + int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; + int had_comma; if (evaluate) { @@ -1173,10 +1177,10 @@ get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error) return FAIL; } - *arg = skipwhite(*arg + 1); + *arg = skipwhite_and_linebreak(*arg + 1, evalarg); while (**arg != ']' && **arg != NUL) { - if (eval1(arg, &tv, flags) == FAIL) // recursive! + if (eval1(arg, &tv, evalarg) == FAIL) // recursive! goto failret; if (evaluate) { @@ -1191,15 +1195,30 @@ get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error) clear_tv(&tv); } + // the comma must come after the value + had_comma = **arg == ','; + if (had_comma) + { + if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1])) + { + semsg(_(e_white_after), ","); + goto failret; + } + *arg = skipwhite(*arg + 1); + } + + // The "]" can be on the next line. But a double quoted string may + // follow, not a comment. + *arg = skipwhite_and_linebreak(*arg, evalarg); if (**arg == ']') break; - if (**arg != ',') + + if (!had_comma) { if (do_error) semsg(_("E696: Missing comma in List: %s"), *arg); goto failret; } - *arg = skipwhite(*arg + 1); } if (**arg != ']') @@ -2338,7 +2357,7 @@ f_insert(typval_T *argvars, typval_T *rettv) } if (l != NULL) { - list_insert_tv(l, &argvars[1], item); + (void)list_insert_tv(l, &argvars[1], item); copy_tv(&argvars[0], rettv); } } @@ -2457,8 +2476,10 @@ f_reduce(typval_T *argvars, typval_T *rettv) list_T *l = argvars[0].vval.v_list; listitem_T *li = NULL; int r; + int called_emsg_start = called_emsg; - CHECK_LIST_MATERIALIZE(l); + if (l != NULL) + CHECK_LIST_MATERIALIZE(l); if (argvars[2].v_type == VAR_UNKNOWN) { if (l == NULL || l->lv_first == NULL) @@ -2475,17 +2496,24 @@ f_reduce(typval_T *argvars, typval_T *rettv) if (l != NULL) li = l->lv_first; } - copy_tv(&initial, rettv); - for ( ; li != NULL; li = li->li_next) + + if (l != NULL) { - argv[0] = *rettv; - argv[1] = li->li_tv; - rettv->v_type = VAR_UNKNOWN; - r = call_func(func_name, -1, rettv, 2, argv, &funcexe); - clear_tv(&argv[0]); - if (r == FAIL) - return; + int prev_locked = l->lv_lock; + + l->lv_lock = VAR_FIXED; // disallow the list changing here + for ( ; li != NULL; li = li->li_next) + { + argv[0] = *rettv; + argv[1] = li->li_tv; + rettv->v_type = VAR_UNKNOWN; + r = call_func(func_name, -1, rettv, 2, argv, &funcexe); + clear_tv(&argv[0]); + if (r == FAIL || called_emsg != called_emsg_start) + break; + } + l->lv_lock = prev_locked; } } else diff --git a/src/map.c b/src/map.c index d5918a42bc..7f3ca5fc0a 100644 --- a/src/map.c +++ b/src/map.c @@ -1614,7 +1614,7 @@ eval_map_expr( save_cursor = curwin->w_cursor; save_msg_col = msg_col; save_msg_row = msg_row; - p = eval_to_string(expr, NULL, FALSE); + p = eval_to_string(expr, FALSE); --textwinlock; --ex_normal_lock; curwin->w_cursor = save_cursor; diff --git a/src/match.c b/src/match.c new file mode 100644 index 0000000000..024ba374f0 --- /dev/null +++ b/src/match.c @@ -0,0 +1,1351 @@ +/* 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. + */ + +/* + * match.c: functions for highlighting matches + */ + +#include "vim.h" + +#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) + +# define SEARCH_HL_PRIORITY 0 + +/* + * Add match to the match list of window 'wp'. The pattern 'pat' will be + * highlighted with the group 'grp' with priority 'prio'. + * Optionally, a desired ID 'id' can be specified (greater than or equal to 1). + * If no particular ID is desired, -1 must be specified for 'id'. + * Return ID of added match, -1 on failure. + */ + static int +match_add( + win_T *wp, + char_u *grp, + char_u *pat, + int prio, + int id, + list_T *pos_list, + char_u *conceal_char UNUSED) // pointer to conceal replacement char +{ + matchitem_T *cur; + matchitem_T *prev; + matchitem_T *m; + int hlg_id; + regprog_T *regprog = NULL; + int rtype = SOME_VALID; + + if (*grp == NUL || (pat != NULL && *pat == NUL)) + return -1; + if (id < -1 || id == 0) + { + semsg(_("E799: Invalid ID: %d (must be greater than or equal to 1)"), + id); + return -1; + } + if (id != -1) + { + cur = wp->w_match_head; + while (cur != NULL) + { + if (cur->id == id) + { + semsg(_("E801: ID already taken: %d"), id); + return -1; + } + cur = cur->next; + } + } + if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0) + { + semsg(_(e_nogroup), grp); + return -1; + } + if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) + { + semsg(_(e_invarg2), pat); + return -1; + } + + // Find available match ID. + while (id == -1) + { + cur = wp->w_match_head; + while (cur != NULL && cur->id != wp->w_next_match_id) + cur = cur->next; + if (cur == NULL) + id = wp->w_next_match_id; + wp->w_next_match_id++; + } + + // Build new match. + m = ALLOC_CLEAR_ONE(matchitem_T); + m->id = id; + m->priority = prio; + m->pattern = pat == NULL ? NULL : vim_strsave(pat); + m->hlg_id = hlg_id; + m->match.regprog = regprog; + m->match.rmm_ic = FALSE; + m->match.rmm_maxcol = 0; +# if defined(FEAT_CONCEAL) + m->conceal_char = 0; + if (conceal_char != NULL) + m->conceal_char = (*mb_ptr2char)(conceal_char); +# endif + + // Set up position matches + if (pos_list != NULL) + { + linenr_T toplnum = 0; + linenr_T botlnum = 0; + listitem_T *li; + int i; + + CHECK_LIST_MATERIALIZE(pos_list); + for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH; + i++, li = li->li_next) + { + linenr_T lnum = 0; + colnr_T col = 0; + int len = 1; + list_T *subl; + listitem_T *subli; + int error = FALSE; + + if (li->li_tv.v_type == VAR_LIST) + { + subl = li->li_tv.vval.v_list; + if (subl == NULL) + goto fail; + subli = subl->lv_first; + if (subli == NULL) + goto fail; + lnum = tv_get_number_chk(&subli->li_tv, &error); + if (error == TRUE) + goto fail; + if (lnum == 0) + { + --i; + continue; + } + m->pos.pos[i].lnum = lnum; + subli = subli->li_next; + if (subli != NULL) + { + col = tv_get_number_chk(&subli->li_tv, &error); + if (error == TRUE) + goto fail; + subli = subli->li_next; + if (subli != NULL) + { + len = tv_get_number_chk(&subli->li_tv, &error); + if (error == TRUE) + goto fail; + } + } + m->pos.pos[i].col = col; + m->pos.pos[i].len = len; + } + else if (li->li_tv.v_type == VAR_NUMBER) + { + if (li->li_tv.vval.v_number == 0) + { + --i; + continue; + } + m->pos.pos[i].lnum = li->li_tv.vval.v_number; + m->pos.pos[i].col = 0; + m->pos.pos[i].len = 0; + } + else + { + emsg(_("E290: List or number required")); + goto fail; + } + if (toplnum == 0 || lnum < toplnum) + toplnum = lnum; + if (botlnum == 0 || lnum >= botlnum) + botlnum = lnum + 1; + } + + // Calculate top and bottom lines for redrawing area + if (toplnum != 0) + { + if (wp->w_buffer->b_mod_set) + { + if (wp->w_buffer->b_mod_top > toplnum) + wp->w_buffer->b_mod_top = toplnum; + if (wp->w_buffer->b_mod_bot < botlnum) + wp->w_buffer->b_mod_bot = botlnum; + } + else + { + wp->w_buffer->b_mod_set = TRUE; + wp->w_buffer->b_mod_top = toplnum; + wp->w_buffer->b_mod_bot = botlnum; + wp->w_buffer->b_mod_xlines = 0; + } + m->pos.toplnum = toplnum; + m->pos.botlnum = botlnum; + rtype = VALID; + } + } + + // Insert new match. The match list is in ascending order with regard to + // the match priorities. + cur = wp->w_match_head; + prev = cur; + while (cur != NULL && prio >= cur->priority) + { + prev = cur; + cur = cur->next; + } + if (cur == prev) + wp->w_match_head = m; + else + prev->next = m; + m->next = cur; + + redraw_win_later(wp, rtype); + return id; + +fail: + vim_free(m); + return -1; +} + +/* + * Delete match with ID 'id' in the match list of window 'wp'. + * Print error messages if 'perr' is TRUE. + */ + static int +match_delete(win_T *wp, int id, int perr) +{ + matchitem_T *cur = wp->w_match_head; + matchitem_T *prev = cur; + int rtype = SOME_VALID; + + if (id < 1) + { + if (perr == TRUE) + semsg(_("E802: Invalid ID: %d (must be greater than or equal to 1)"), + id); + return -1; + } + while (cur != NULL && cur->id != id) + { + prev = cur; + cur = cur->next; + } + if (cur == NULL) + { + if (perr == TRUE) + semsg(_("E803: ID not found: %d"), id); + return -1; + } + if (cur == prev) + wp->w_match_head = cur->next; + else + prev->next = cur->next; + vim_regfree(cur->match.regprog); + vim_free(cur->pattern); + if (cur->pos.toplnum != 0) + { + if (wp->w_buffer->b_mod_set) + { + if (wp->w_buffer->b_mod_top > cur->pos.toplnum) + wp->w_buffer->b_mod_top = cur->pos.toplnum; + if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) + wp->w_buffer->b_mod_bot = cur->pos.botlnum; + } + else + { + wp->w_buffer->b_mod_set = TRUE; + wp->w_buffer->b_mod_top = cur->pos.toplnum; + wp->w_buffer->b_mod_bot = cur->pos.botlnum; + wp->w_buffer->b_mod_xlines = 0; + } + rtype = VALID; + } + vim_free(cur); + redraw_win_later(wp, rtype); + return 0; +} + +/* + * Delete all matches in the match list of window 'wp'. + */ + void +clear_matches(win_T *wp) +{ + matchitem_T *m; + + while (wp->w_match_head != NULL) + { + m = wp->w_match_head->next; + vim_regfree(wp->w_match_head->match.regprog); + vim_free(wp->w_match_head->pattern); + vim_free(wp->w_match_head); + wp->w_match_head = m; + } + redraw_win_later(wp, SOME_VALID); +} + +/* + * Get match from ID 'id' in window 'wp'. + * Return NULL if match not found. + */ + static matchitem_T * +get_match(win_T *wp, int id) +{ + matchitem_T *cur = wp->w_match_head; + + while (cur != NULL && cur->id != id) + cur = cur->next; + return cur; +} + +/* + * Init for calling prepare_search_hl(). + */ + void +init_search_hl(win_T *wp, match_T *search_hl) +{ + matchitem_T *cur; + + // Setup for match and 'hlsearch' highlighting. Disable any previous + // match + cur = wp->w_match_head; + while (cur != NULL) + { + cur->hl.rm = cur->match; + if (cur->hlg_id == 0) + cur->hl.attr = 0; + else + cur->hl.attr = syn_id2attr(cur->hlg_id); + cur->hl.buf = wp->w_buffer; + cur->hl.lnum = 0; + cur->hl.first_lnum = 0; +# ifdef FEAT_RELTIME + // Set the time limit to 'redrawtime'. + profile_setlimit(p_rdt, &(cur->hl.tm)); +# endif + cur = cur->next; + } + search_hl->buf = wp->w_buffer; + search_hl->lnum = 0; + search_hl->first_lnum = 0; + // time limit is set at the toplevel, for all windows +} + +/* + * If there is a match fill "shl" and return one. + * Return zero otherwise. + */ + static int +next_search_hl_pos( + match_T *shl, // points to a match + linenr_T lnum, + posmatch_T *posmatch, // match positions + colnr_T mincol) // minimal column for a match +{ + int i; + int found = -1; + + for (i = posmatch->cur; i < MAXPOSMATCH; i++) + { + llpos_T *pos = &posmatch->pos[i]; + + if (pos->lnum == 0) + break; + if (pos->len == 0 && pos->col < mincol) + continue; + if (pos->lnum == lnum) + { + if (found >= 0) + { + // if this match comes before the one at "found" then swap + // them + if (pos->col < posmatch->pos[found].col) + { + llpos_T tmp = *pos; + + *pos = posmatch->pos[found]; + posmatch->pos[found] = tmp; + } + } + else + found = i; + } + } + posmatch->cur = 0; + if (found >= 0) + { + colnr_T start = posmatch->pos[found].col == 0 + ? 0 : posmatch->pos[found].col - 1; + colnr_T end = posmatch->pos[found].col == 0 + ? MAXCOL : start + posmatch->pos[found].len; + + shl->lnum = lnum; + shl->rm.startpos[0].lnum = 0; + shl->rm.startpos[0].col = start; + shl->rm.endpos[0].lnum = 0; + shl->rm.endpos[0].col = end; + shl->is_addpos = TRUE; + posmatch->cur = found + 1; + return 1; + } + return 0; +} + +/* + * Search for a next 'hlsearch' or match. + * Uses shl->buf. + * Sets shl->lnum and shl->rm contents. + * Note: Assumes a previous match is always before "lnum", unless + * shl->lnum is zero. + * Careful: Any pointers for buffer lines will become invalid. + */ + static void +next_search_hl( + win_T *win, + match_T *search_hl, + match_T *shl, // points to search_hl or a match + linenr_T lnum, + colnr_T mincol, // minimal column for a match + matchitem_T *cur) // to retrieve match positions if any +{ + linenr_T l; + colnr_T matchcol; + long nmatched; + int called_emsg_before = called_emsg; + + // for :{range}s/pat only highlight inside the range + if (lnum < search_first_line || lnum > search_last_line) + { + shl->lnum = 0; + return; + } + + if (shl->lnum != 0) + { + // Check for three situations: + // 1. If the "lnum" is below a previous match, start a new search. + // 2. If the previous match includes "mincol", use it. + // 3. Continue after the previous match. + l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum; + if (lnum > l) + shl->lnum = 0; + else if (lnum < l || shl->rm.endpos[0].col > mincol) + return; + } + + // Repeat searching for a match until one is found that includes "mincol" + // or none is found in this line. + for (;;) + { +# ifdef FEAT_RELTIME + // Stop searching after passing the time limit. + if (profile_passed_limit(&(shl->tm))) + { + shl->lnum = 0; // no match found in time + break; + } +# endif + // Three situations: + // 1. No useful previous match: search from start of line. + // 2. Not Vi compatible or empty match: continue at next character. + // Break the loop if this is beyond the end of the line. + // 3. Vi compatible searching: continue at end of previous match. + if (shl->lnum == 0) + matchcol = 0; + else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL + || (shl->rm.endpos[0].lnum == 0 + && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) + { + char_u *ml; + + matchcol = shl->rm.startpos[0].col; + ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol; + if (*ml == NUL) + { + ++matchcol; + shl->lnum = 0; + break; + } + if (has_mbyte) + matchcol += mb_ptr2len(ml); + else + ++matchcol; + } + else + matchcol = shl->rm.endpos[0].col; + + shl->lnum = lnum; + if (shl->rm.regprog != NULL) + { + // Remember whether shl->rm is using a copy of the regprog in + // cur->match. + int regprog_is_copy = (shl != search_hl && cur != NULL + && shl == &cur->hl + && cur->match.regprog == cur->hl.rm.regprog); + int timed_out = FALSE; + + nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, + matchcol, +#ifdef FEAT_RELTIME + &(shl->tm), &timed_out +#else + NULL, NULL +#endif + ); + // Copy the regprog, in case it got freed and recompiled. + if (regprog_is_copy) + cur->match.regprog = cur->hl.rm.regprog; + + if (called_emsg > called_emsg_before || got_int || timed_out) + { + // Error while handling regexp: stop using this regexp. + if (shl == search_hl) + { + // don't free regprog in the match list, it's a copy + vim_regfree(shl->rm.regprog); + set_no_hlsearch(TRUE); + } + shl->rm.regprog = NULL; + shl->lnum = 0; + got_int = FALSE; // avoid the "Type :quit to exit Vim" message + break; + } + } + else if (cur != NULL) + nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); + else + nmatched = 0; + if (nmatched == 0) + { + shl->lnum = 0; // no match found + break; + } + if (shl->rm.startpos[0].lnum > 0 + || shl->rm.startpos[0].col >= mincol + || nmatched > 1 + || shl->rm.endpos[0].col > mincol) + { + shl->lnum += shl->rm.startpos[0].lnum; + break; // useful match found + } + } +} + +/* + * Advance to the match in window "wp" line "lnum" or past it. + */ + void +prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) +{ + matchitem_T *cur; // points to the match list + match_T *shl; // points to search_hl or a match + int shl_flag; // flag to indicate whether search_hl + // has been processed or not + int pos_inprogress; // marks that position match search is + // in progress + int n; + + // When using a multi-line pattern, start searching at the top + // of the window or just after a closed fold. + // Do this both for search_hl and the match list. + cur = wp->w_match_head; + shl_flag = WIN_IS_POPUP(wp); // skip search_hl in a popup window + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE) + { + shl = search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; + if (shl->rm.regprog != NULL + && shl->lnum == 0 + && re_multiline(shl->rm.regprog)) + { + if (shl->first_lnum == 0) + { +# ifdef FEAT_FOLDING + for (shl->first_lnum = lnum; + shl->first_lnum > wp->w_topline; --shl->first_lnum) + if (hasFoldingWin(wp, shl->first_lnum - 1, + NULL, NULL, TRUE, NULL)) + break; +# else + shl->first_lnum = wp->w_topline; +# endif + } + if (cur != NULL) + cur->pos.cur = 0; + pos_inprogress = TRUE; + n = 0; + while (shl->first_lnum < lnum && (shl->rm.regprog != NULL + || (cur != NULL && pos_inprogress))) + { + next_search_hl(wp, search_hl, shl, shl->first_lnum, (colnr_T)n, + shl == search_hl ? NULL : cur); + pos_inprogress = cur == NULL || cur->pos.cur == 0 + ? FALSE : TRUE; + if (shl->lnum != 0) + { + shl->first_lnum = shl->lnum + + shl->rm.endpos[0].lnum + - shl->rm.startpos[0].lnum; + n = shl->rm.endpos[0].col; + } + else + { + ++shl->first_lnum; + n = 0; + } + } + } + if (shl != search_hl && cur != NULL) + cur = cur->next; + } +} + +/* + * Prepare for 'hlsearch' and match highlighting in one window line. + * Return TRUE if there is such highlighting and set "search_attr" to the + * current highlight attribute. + */ + int +prepare_search_hl_line( + win_T *wp, + linenr_T lnum, + colnr_T mincol, + char_u **line, + match_T *search_hl, + int *search_attr) +{ + matchitem_T *cur; // points to the match list + match_T *shl; // points to search_hl or a match + int shl_flag; // flag to indicate whether search_hl + // has been processed or not + int area_highlighting = FALSE; + + // Handle highlighting the last used search pattern and matches. + // Do this for both search_hl and the match list. + // Do not use search_hl in a popup window. + cur = wp->w_match_head; + shl_flag = WIN_IS_POPUP(wp); + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE) + { + shl = search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; + shl->startcol = MAXCOL; + shl->endcol = MAXCOL; + shl->attr_cur = 0; + shl->is_addpos = FALSE; + if (cur != NULL) + cur->pos.cur = 0; + next_search_hl(wp, search_hl, shl, lnum, mincol, + shl == search_hl ? NULL : cur); + + // Need to get the line again, a multi-line regexp may have made it + // invalid. + *line = ml_get_buf(wp->w_buffer, lnum, FALSE); + + if (shl->lnum != 0 && shl->lnum <= lnum) + { + if (shl->lnum == lnum) + shl->startcol = shl->rm.startpos[0].col; + else + shl->startcol = 0; + if (lnum == shl->lnum + shl->rm.endpos[0].lnum + - shl->rm.startpos[0].lnum) + shl->endcol = shl->rm.endpos[0].col; + else + shl->endcol = MAXCOL; + // Highlight one character for an empty match. + if (shl->startcol == shl->endcol) + { + if (has_mbyte && (*line)[shl->endcol] != NUL) + shl->endcol += (*mb_ptr2len)((*line) + shl->endcol); + else + ++shl->endcol; + } + if ((long)shl->startcol < mincol) // match at leftcol + { + shl->attr_cur = shl->attr; + *search_attr = shl->attr; + } + area_highlighting = TRUE; + } + if (shl != search_hl && cur != NULL) + cur = cur->next; + } + return area_highlighting; +} + +/* + * For a position in a line: Check for start/end of 'hlsearch' and other + * matches. + * After end, check for start/end of next match. + * When another match, have to check for start again. + * Watch out for matching an empty string! + * Return the updated search_attr. + */ + int +update_search_hl( + win_T *wp, + linenr_T lnum, + colnr_T col, + char_u **line, + match_T *search_hl, + int *has_match_conc UNUSED, + int *match_conc UNUSED, + int did_line_attr, + int lcs_eol_one) +{ + matchitem_T *cur; // points to the match list + match_T *shl; // points to search_hl or a match + int shl_flag; // flag to indicate whether search_hl + // has been processed or not + int pos_inprogress; // marks that position match search is in + // progress + int search_attr = 0; + + + // Do this for 'search_hl' and the match list (ordered by priority). + cur = wp->w_match_head; + shl_flag = WIN_IS_POPUP(wp); + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE + && (cur == NULL + || cur->priority > SEARCH_HL_PRIORITY)) + { + shl = search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; + if (cur != NULL) + cur->pos.cur = 0; + pos_inprogress = TRUE; + while (shl->rm.regprog != NULL || (cur != NULL && pos_inprogress)) + { + if (shl->startcol != MAXCOL + && col >= shl->startcol + && col < shl->endcol) + { + int next_col = col + mb_ptr2len(*line + col); + + if (shl->endcol < next_col) + shl->endcol = next_col; + shl->attr_cur = shl->attr; +# ifdef FEAT_CONCEAL + // Match with the "Conceal" group results in hiding + // the match. + if (cur != NULL + && shl != search_hl + && syn_name2id((char_u *)"Conceal") == cur->hlg_id) + { + *has_match_conc = col == shl->startcol ? 2 : 1; + *match_conc = cur->conceal_char; + } + else + *has_match_conc = 0; +# endif + } + else if (col == shl->endcol) + { + shl->attr_cur = 0; + next_search_hl(wp, search_hl, shl, lnum, col, + shl == search_hl ? NULL : cur); + pos_inprogress = !(cur == NULL || cur->pos.cur == 0); + + // Need to get the line again, a multi-line regexp may have + // made it invalid. + *line = ml_get_buf(wp->w_buffer, lnum, FALSE); + + if (shl->lnum == lnum) + { + shl->startcol = shl->rm.startpos[0].col; + if (shl->rm.endpos[0].lnum == 0) + shl->endcol = shl->rm.endpos[0].col; + else + shl->endcol = MAXCOL; + + if (shl->startcol == shl->endcol) + { + // highlight empty match, try again after + // it + if (has_mbyte) + shl->endcol += (*mb_ptr2len)(*line + shl->endcol); + else + ++shl->endcol; + } + + // Loop to check if the match starts at the + // current position + continue; + } + } + break; + } + if (shl != search_hl && cur != NULL) + cur = cur->next; + } + + // Use attributes from match with highest priority among 'search_hl' and + // the match list. + cur = wp->w_match_head; + shl_flag = WIN_IS_POPUP(wp); + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE + && (cur == NULL || + cur->priority > SEARCH_HL_PRIORITY)) + { + shl = search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; + if (shl->attr_cur != 0) + search_attr = shl->attr_cur; + if (shl != search_hl && cur != NULL) + cur = cur->next; + } + // Only highlight one character after the last column. + if (*(*line + col) == NUL && (did_line_attr >= 1 + || (wp->w_p_list && lcs_eol_one == -1))) + search_attr = 0; + return search_attr; +} + + int +get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol) +{ + long prevcol = curcol; + int prevcol_hl_flag = FALSE; + matchitem_T *cur; // points to the match list + + // we're not really at that column when skipping some text + if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) + ++prevcol; + + if (!search_hl->is_addpos && prevcol == (long)search_hl->startcol) + prevcol_hl_flag = TRUE; + else + { + cur = wp->w_match_head; + while (cur != NULL) + { + if (!cur->hl.is_addpos && prevcol == (long)cur->hl.startcol) + { + prevcol_hl_flag = TRUE; + break; + } + cur = cur->next; + } + } + return prevcol_hl_flag; +} + +/* + * Get highlighting for the char after the text in "char_attr" from 'hlsearch' + * or match highlighting. + */ + void +get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr) +{ + matchitem_T *cur; // points to the match list + match_T *shl; // points to search_hl or a match + int shl_flag; // flag to indicate whether search_hl + // has been processed or not + + cur = wp->w_match_head; + shl_flag = WIN_IS_POPUP(wp); + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE + && ((cur != NULL + && cur->priority > SEARCH_HL_PRIORITY) + || cur == NULL)) + { + shl = search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; + if (col - 1 == (long)shl->startcol + && (shl == search_hl || !shl->is_addpos)) + *char_attr = shl->attr; + if (shl != search_hl && cur != NULL) + cur = cur->next; + } +} + +#endif // FEAT_SEARCH_EXTRA + +#if defined(FEAT_EVAL) || defined(PROTO) +# ifdef FEAT_SEARCH_EXTRA + static int +matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win) +{ + dictitem_T *di; + + if (tv->v_type != VAR_DICT) + { + emsg(_(e_dictreq)); + return FAIL; + } + + if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL) + *conceal_char = dict_get_string(tv->vval.v_dict, + (char_u *)"conceal", FALSE); + + if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL) + { + *win = find_win_by_nr_or_id(&di->di_tv); + if (*win == NULL) + { + emsg(_(e_invalwindow)); + return FAIL; + } + } + + return OK; +} +#endif + +/* + * "clearmatches()" function + */ + void +f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +#ifdef FEAT_SEARCH_EXTRA + win_T *win = get_optional_window(argvars, 0); + + if (win != NULL) + clear_matches(win); +#endif +} + +/* + * "getmatches()" function + */ + void +f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +# ifdef FEAT_SEARCH_EXTRA + dict_T *dict; + matchitem_T *cur; + int i; + win_T *win = get_optional_window(argvars, 0); + + if (rettv_list_alloc(rettv) == FAIL || win == NULL) + return; + + cur = win->w_match_head; + while (cur != NULL) + { + dict = dict_alloc(); + if (dict == NULL) + return; + if (cur->match.regprog == NULL) + { + // match added with matchaddpos() + for (i = 0; i < MAXPOSMATCH; ++i) + { + llpos_T *llpos; + char buf[30]; // use 30 to avoid compiler warning + list_T *l; + + llpos = &cur->pos.pos[i]; + if (llpos->lnum == 0) + break; + l = list_alloc(); + if (l == NULL) + break; + list_append_number(l, (varnumber_T)llpos->lnum); + if (llpos->col > 0) + { + list_append_number(l, (varnumber_T)llpos->col); + list_append_number(l, (varnumber_T)llpos->len); + } + sprintf(buf, "pos%d", i + 1); + dict_add_list(dict, buf, l); + } + } + else + { + dict_add_string(dict, "pattern", cur->pattern); + } + dict_add_string(dict, "group", syn_id2name(cur->hlg_id)); + dict_add_number(dict, "priority", (long)cur->priority); + dict_add_number(dict, "id", (long)cur->id); +# if defined(FEAT_CONCEAL) + if (cur->conceal_char) + { + char_u buf[MB_MAXBYTES + 1]; + + buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; + dict_add_string(dict, "conceal", (char_u *)&buf); + } +# endif + list_append_dict(rettv->vval.v_list, dict); + cur = cur->next; + } +# endif +} + +/* + * "setmatches()" function + */ + void +f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +#ifdef FEAT_SEARCH_EXTRA + list_T *l; + listitem_T *li; + dict_T *d; + list_T *s = NULL; + win_T *win = get_optional_window(argvars, 1); + + rettv->vval.v_number = -1; + if (argvars[0].v_type != VAR_LIST) + { + emsg(_(e_listreq)); + return; + } + if (win == NULL) + return; + + if ((l = argvars[0].vval.v_list) != NULL) + { + // To some extent make sure that we are dealing with a list from + // "getmatches()". + li = l->lv_first; + while (li != NULL) + { + if (li->li_tv.v_type != VAR_DICT + || (d = li->li_tv.vval.v_dict) == NULL) + { + emsg(_(e_invarg)); + return; + } + if (!(dict_find(d, (char_u *)"group", -1) != NULL + && (dict_find(d, (char_u *)"pattern", -1) != NULL + || dict_find(d, (char_u *)"pos1", -1) != NULL) + && dict_find(d, (char_u *)"priority", -1) != NULL + && dict_find(d, (char_u *)"id", -1) != NULL)) + { + emsg(_(e_invarg)); + return; + } + li = li->li_next; + } + + clear_matches(win); + li = l->lv_first; + while (li != NULL) + { + int i = 0; + char buf[30]; // use 30 to avoid compiler warning + dictitem_T *di; + char_u *group; + int priority; + int id; + char_u *conceal; + + d = li->li_tv.vval.v_dict; + if (dict_find(d, (char_u *)"pattern", -1) == NULL) + { + if (s == NULL) + { + s = list_alloc(); + if (s == NULL) + return; + } + + // match from matchaddpos() + for (i = 1; i < 9; i++) + { + sprintf((char *)buf, (char *)"pos%d", i); + if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) + { + if (di->di_tv.v_type != VAR_LIST) + return; + + list_append_tv(s, &di->di_tv); + s->lv_refcount++; + } + else + break; + } + } + + group = dict_get_string(d, (char_u *)"group", TRUE); + priority = (int)dict_get_number(d, (char_u *)"priority"); + id = (int)dict_get_number(d, (char_u *)"id"); + conceal = dict_find(d, (char_u *)"conceal", -1) != NULL + ? dict_get_string(d, (char_u *)"conceal", TRUE) + : NULL; + if (i == 0) + { + match_add(win, group, + dict_get_string(d, (char_u *)"pattern", FALSE), + priority, id, NULL, conceal); + } + else + { + match_add(win, group, NULL, priority, id, s, conceal); + list_unref(s); + s = NULL; + } + vim_free(group); + vim_free(conceal); + + li = li->li_next; + } + rettv->vval.v_number = 0; + } +#endif +} + +/* + * "matchadd()" function + */ + void +f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +# ifdef FEAT_SEARCH_EXTRA + char_u buf[NUMBUFLEN]; + char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); // group + char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); // pattern + int prio = 10; // default priority + int id = -1; + int error = FALSE; + char_u *conceal_char = NULL; + win_T *win = curwin; + + rettv->vval.v_number = -1; + + if (grp == NULL || pat == NULL) + return; + if (argvars[2].v_type != VAR_UNKNOWN) + { + prio = (int)tv_get_number_chk(&argvars[2], &error); + if (argvars[3].v_type != VAR_UNKNOWN) + { + id = (int)tv_get_number_chk(&argvars[3], &error); + if (argvars[4].v_type != VAR_UNKNOWN + && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) + return; + } + } + if (error == TRUE) + return; + if (id >= 1 && id <= 3) + { + semsg(_("E798: ID is reserved for \":match\": %d"), id); + return; + } + + rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL, + conceal_char); +# endif +} + +/* + * "matchaddpos()" function + */ + void +f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +# ifdef FEAT_SEARCH_EXTRA + char_u buf[NUMBUFLEN]; + char_u *group; + int prio = 10; + int id = -1; + int error = FALSE; + list_T *l; + char_u *conceal_char = NULL; + win_T *win = curwin; + + rettv->vval.v_number = -1; + + group = tv_get_string_buf_chk(&argvars[0], buf); + if (group == NULL) + return; + + if (argvars[1].v_type != VAR_LIST) + { + semsg(_(e_listarg), "matchaddpos()"); + return; + } + l = argvars[1].vval.v_list; + if (l == NULL) + return; + + if (argvars[2].v_type != VAR_UNKNOWN) + { + prio = (int)tv_get_number_chk(&argvars[2], &error); + if (argvars[3].v_type != VAR_UNKNOWN) + { + id = (int)tv_get_number_chk(&argvars[3], &error); + + if (argvars[4].v_type != VAR_UNKNOWN + && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL) + return; + } + } + if (error == TRUE) + return; + + // id == 3 is ok because matchaddpos() is supposed to substitute :3match + if (id == 1 || id == 2) + { + semsg(_("E798: ID is reserved for \":match\": %d"), id); + return; + } + + rettv->vval.v_number = match_add(win, group, NULL, prio, id, l, + conceal_char); +# endif +} + +/* + * "matcharg()" function + */ + void +f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) +{ + if (rettv_list_alloc(rettv) == OK) + { +# ifdef FEAT_SEARCH_EXTRA + int id = (int)tv_get_number(&argvars[0]); + matchitem_T *m; + + if (id >= 1 && id <= 3) + { + if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) + { + list_append_string(rettv->vval.v_list, + syn_id2name(m->hlg_id), -1); + list_append_string(rettv->vval.v_list, m->pattern, -1); + } + else + { + list_append_string(rettv->vval.v_list, NULL, -1); + list_append_string(rettv->vval.v_list, NULL, -1); + } + } +# endif + } +} + +/* + * "matchdelete()" function + */ + void +f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +# ifdef FEAT_SEARCH_EXTRA + win_T *win = get_optional_window(argvars, 1); + + if (win == NULL) + rettv->vval.v_number = -1; + else + rettv->vval.v_number = match_delete(win, + (int)tv_get_number(&argvars[0]), TRUE); +# endif +} +#endif + +#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) +/* + * ":[N]match {group} {pattern}" + * Sets nextcmd to the start of the next command, if any. Also called when + * skipping commands to find the next command. + */ + void +ex_match(exarg_T *eap) +{ + char_u *p; + char_u *g = NULL; + char_u *end; + int c; + int id; + + if (eap->line2 <= 3) + id = eap->line2; + else + { + emsg(_(e_invcmd)); + return; + } + + // First clear any old pattern. + if (!eap->skip) + match_delete(curwin, id, FALSE); + + if (ends_excmd2(eap->cmd, eap->arg)) + end = eap->arg; + else if ((STRNICMP(eap->arg, "none", 4) == 0 + && (VIM_ISWHITE(eap->arg[4]) + || ends_excmd2(eap->arg, eap->arg + 4)))) + end = eap->arg + 4; + else + { + p = skiptowhite(eap->arg); + if (!eap->skip) + g = vim_strnsave(eap->arg, p - eap->arg); + p = skipwhite(p); + if (*p == NUL) + { + // There must be two arguments. + vim_free(g); + semsg(_(e_invarg2), eap->arg); + return; + } + end = skip_regexp(p + 1, *p, TRUE); + if (!eap->skip) + { + if (*end != NUL && !ends_excmd2(end, skipwhite(end + 1))) + { + vim_free(g); + eap->errmsg = e_trailing; + return; + } + if (*end != *p) + { + vim_free(g); + semsg(_(e_invarg2), p); + return; + } + + c = *end; + *end = NUL; + match_add(curwin, g, p + 1, 10, id, NULL, NULL); + vim_free(g); + *end = c; + } + } + eap->nextcmd = find_nextcmd(end); +} +#endif diff --git a/src/message.c b/src/message.c index 604f96ea73..f77487c6fc 100644 --- a/src/message.c +++ b/src/message.c @@ -3657,6 +3657,7 @@ do_dialog( char_u *hotkeys; int c; int i; + tmode_T save_tmode; #ifndef NO_CONSOLE // Don't output anything in silent mode ("ex -s") @@ -3688,6 +3689,10 @@ do_dialog( State = CONFIRM; setmouse(); + // Ensure raw mode here. + save_tmode = cur_tmode; + settmode(TMODE_RAW); + /* * Since we wait for a keypress, don't make the * user press RETURN as well afterwards. @@ -3748,6 +3753,7 @@ do_dialog( vim_free(hotkeys); } + settmode(save_tmode); State = oldState; setmouse(); --no_wait_return; diff --git a/src/mouse.c b/src/mouse.c index 3459c53aa7..6f3169f88e 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -2160,6 +2160,7 @@ check_termcode_mouse( # endif int mouse_code = 0; // init for GCC int is_click, is_drag; + int is_release, release_is_ambiguous; int wheel_code = 0; int current_button; static int held_button = MOUSE_RELEASE; @@ -2174,7 +2175,7 @@ check_termcode_mouse( long timediff; // elapsed time in msec # endif - is_click = is_drag = FALSE; + is_click = is_drag = is_release = release_is_ambiguous = FALSE; # if !defined(UNIX) || defined(FEAT_MOUSE_XTERM) || defined(FEAT_GUI) \ || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE) @@ -2297,9 +2298,6 @@ check_termcode_mouse( || key_name[0] == KS_SGR_MOUSE_RELEASE) mouse_code += 32; - if (key_name[0] == KS_SGR_MOUSE_RELEASE) - mouse_code |= MOUSE_RELEASE; - mouse_col = getdigits(&p) - 1; if (*p++ != ';') return -1; @@ -2311,6 +2309,19 @@ check_termcode_mouse( *modifiers = 0; } + if (key_name[0] == KS_SGR_MOUSE + || key_name[0] == KS_SGR_MOUSE_RELEASE) + { + if (key_name[0] == KS_SGR_MOUSE_RELEASE) + is_release = TRUE; + } + else + { + release_is_ambiguous = TRUE; + if ((mouse_code & MOUSE_RELEASE) == MOUSE_RELEASE) + is_release = TRUE; + } + if (key_name[0] == KS_MOUSE # ifdef FEAT_MOUSE_GPM || key_name[0] == KS_GPM_MOUSE @@ -2372,7 +2383,7 @@ check_termcode_mouse( # ifdef FEAT_XCLIPBOARD else if (!(mouse_code & MOUSE_DRAG & ~MOUSE_CLICK_MASK)) { - if ((mouse_code & MOUSE_RELEASE) == MOUSE_RELEASE) + if (is_release) stop_xterm_trace(); else start_xterm_trace(mouse_code); @@ -2510,12 +2521,13 @@ check_termcode_mouse( if (button & 16) mouse_code |= MOUSE_CTRL; break; case 'u': // Button Up + is_release = TRUE; if (button & 1) - mouse_code |= MOUSE_LEFT | MOUSE_RELEASE; + mouse_code |= MOUSE_LEFT; if (button & 2) - mouse_code |= MOUSE_MIDDLE | MOUSE_RELEASE; + mouse_code |= MOUSE_MIDDLE; if (button & 4) - mouse_code |= MOUSE_RIGHT | MOUSE_RELEASE; + mouse_code |= MOUSE_RIGHT; if (button & 8) mouse_code |= MOUSE_SHIFT; if (button & 16) @@ -2639,17 +2651,20 @@ check_termcode_mouse( case 2: mouse_code = MOUSE_LEFT; WantQueryMouse = TRUE; break; - case 3: mouse_code = MOUSE_RELEASE | MOUSE_LEFT; + case 3: mouse_code = MOUSE_LEFT; + is_release = TRUE; break; case 4: mouse_code = MOUSE_MIDDLE; WantQueryMouse = TRUE; break; - case 5: mouse_code = MOUSE_RELEASE | MOUSE_MIDDLE; + case 5: mouse_code = MOUSE_MIDDLE; + is_release = TRUE; break; case 6: mouse_code = MOUSE_RIGHT; WantQueryMouse = TRUE; break; - case 7: mouse_code = MOUSE_RELEASE | MOUSE_RIGHT; + case 7: mouse_code = MOUSE_RIGHT; + is_release = TRUE; break; case 8: return -1; // fourth button down case 9: return -1; // fourth button up @@ -2702,7 +2717,7 @@ check_termcode_mouse( break; case 32: // Release - mouse_code |= MOUSE_RELEASE; + is_release = TRUE; break; case 33: // Drag @@ -2723,6 +2738,9 @@ check_termcode_mouse( // Interpret the mouse code current_button = (mouse_code & MOUSE_CLICK_MASK); + if (is_release) + current_button |= MOUSE_RELEASE; + if (current_button == MOUSE_RELEASE # ifdef FEAT_MOUSE_XTERM && wheel_code == 0 @@ -2827,15 +2845,22 @@ check_termcode_mouse( // Work out our pseudo mouse event. Note that MOUSE_RELEASE gets // added, then it's not mouse up/down. key_name[0] = KS_EXTRA; - if (wheel_code != 0 - && (wheel_code & MOUSE_RELEASE) != MOUSE_RELEASE) + if (wheel_code != 0 && (!is_release || release_is_ambiguous)) { if (wheel_code & MOUSE_CTRL) *modifiers |= MOD_MASK_CTRL; if (wheel_code & MOUSE_ALT) *modifiers |= MOD_MASK_ALT; - key_name[1] = (wheel_code & 1) - ? (int)KE_MOUSEUP : (int)KE_MOUSEDOWN; + + if (wheel_code & 1 && wheel_code & 2) + key_name[1] = (int)KE_MOUSELEFT; + else if (wheel_code & 2) + key_name[1] = (int)KE_MOUSERIGHT; + else if (wheel_code & 1) + key_name[1] = (int)KE_MOUSEUP; + else + key_name[1] = (int)KE_MOUSEDOWN; + held_button = MOUSE_RELEASE; } else diff --git a/src/move.c b/src/move.c index 3ff656f190..5e58c6b764 100644 --- a/src/move.c +++ b/src/move.c @@ -2710,8 +2710,6 @@ halfpage(int flag, linenr_T Prenum) if (curwin->w_topfill > 0) { i = 1; - if (--n < 0 && scrolled > 0) - break; --curwin->w_topfill; } else diff --git a/src/os_unix.c b/src/os_unix.c index 71ac78bd98..09f63a1bdc 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5944,6 +5944,8 @@ mch_create_pty_channel(job_T *job, jobopt_T *options) channel_T *channel; open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in); + if (pty_master_fd < 0 || pty_slave_fd < 0) + return FAIL; close(pty_slave_fd); channel = add_channel(); diff --git a/src/popupwin.c b/src/popupwin.c index d144be73fe..3461313ec0 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -384,7 +384,7 @@ popup_add_timeout(win_T *wp, int time) vim_snprintf((char *)cbbuf, sizeof(cbbuf), "{_ -> popup_close(%d)}", wp->w_id); - if (get_lambda_tv(&ptr, &tv, TRUE) == OK) + if (get_lambda_tv(&ptr, &tv, &EVALARG_EVALUATE) == OK) { wp->w_popup_timer = create_timer(time, 0); wp->w_popup_timer->tr_callback = get_callback(&tv); diff --git a/src/proto.h b/src/proto.h index 7015adeaa6..0324d6f9a2 100644 --- a/src/proto.h +++ b/src/proto.h @@ -104,6 +104,7 @@ extern int _stricoll(char *a, char *b); # include "main.pro" # include "map.pro" # include "mark.pro" +# include "match.pro" # include "memfile.pro" # include "memline.pro" # ifdef FEAT_MENU diff --git a/src/proto/dict.pro b/src/proto/dict.pro index 45bcfbf3a9..093139f429 100644 --- a/src/proto/dict.pro +++ b/src/proto/dict.pro @@ -32,7 +32,7 @@ varnumber_T dict_get_number(dict_T *d, char_u *key); varnumber_T dict_get_number_def(dict_T *d, char_u *key, int def); varnumber_T dict_get_number_check(dict_T *d, char_u *key); char_u *dict2string(typval_T *tv, int copyID, int restore_copyID); -int eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal); +int eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal); void dict_extend(dict_T *d1, dict_T *d2, char_u *action); dictitem_T *dict_lookup(hashitem_T *hi); int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 57dd8387cd..3e87907957 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -3,16 +3,18 @@ varnumber_T num_divide(varnumber_T n1, varnumber_T n2); varnumber_T num_modulus(varnumber_T n1, varnumber_T n2); void eval_init(void); void eval_clear(void); -int eval_to_bool(char_u *arg, int *error, char_u **nextcmd, int skip); +void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip); +int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip); int eval_expr_valid_arg(typval_T *tv); int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv); int eval_expr_to_bool(typval_T *expr, int *error); -char_u *eval_to_string_skip(char_u *arg, char_u **nextcmd, int skip); +char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip); int skip_expr(char_u **pp); -char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert); -char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox); +int skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg); +char_u *eval_to_string(char_u *arg, int convert); +char_u *eval_to_string_safe(char_u *arg, int use_sandbox); varnumber_T eval_to_number(char_u *expr); -typval_T *eval_expr(char_u *arg, char_u **nextcmd); +typval_T *eval_expr(char_u *arg, exarg_T *eap); int call_vim_function(char_u *func, int argc, typval_T *argv, typval_T *rettv); varnumber_T call_func_retnr(char_u *func, int argc, typval_T *argv); void *call_func_retstr(char_u *func, int argc, typval_T *argv); @@ -21,13 +23,18 @@ int eval_foldexpr(char_u *arg, int *cp); char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags); void clear_lval(lval_T *lp); void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, int flags, char_u *op); -void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip); +void *eval_for_line(char_u *arg, int *errp, exarg_T *eap, evalarg_T *evalarg); +void skip_for_lines(void *fi_void, evalarg_T *evalarg); int next_for_item(void *fi_void, char_u *arg); void free_for_info(void *fi_void); void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx); int pattern_match(char_u *pat, char_u *text, int ic); -int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int flags); -int eval1(char_u **arg, typval_T *rettv, int flags); +char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext); +char_u *eval_next_line(evalarg_T *evalarg); +char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg); +void clear_evalarg(evalarg_T *evalarg, exarg_T *eap); +int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg); +int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg); void eval_addblob(typval_T *tv1, typval_T *tv2); int eval_addlist(typval_T *tv1, typval_T *tv2); char_u *partial_name(partial_T *pt); @@ -51,7 +58,7 @@ int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose); char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags); int eval_isnamec(int c); int eval_isnamec1(int c); -int handle_subscript(char_u **arg, typval_T *rettv, int flags, int verbose, char_u *start_leader, char_u **end_leaderp); +int handle_subscript(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int verbose); int item_copy(typval_T *from, typval_T *to, int deep, int copyID); void echo_one(typval_T *rettv, int with_space, int *atstart, int *needclr); void ex_echo(exarg_T *eap); diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro index eab82c8cfa..a1083100dc 100644 --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -52,7 +52,7 @@ void set_reg_var(int c); char_u *v_exception(char_u *oldval); char_u *v_throwpoint(char_u *oldval); char_u *set_cmdarg(exarg_T *eap, char_u *oldarg); -int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload); +int eval_variable(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload); void check_vars(char_u *name, int len); dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload); dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload); diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 79061eabcc..136e608100 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -4,10 +4,12 @@ int do_cmdline_cmd(char_u *cmd); int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int, int), void *cookie, int flags); int getline_equal(char_u *(*fgetline)(int, void *, int, int), void *cookie, char_u *(*func)(int, void *, int, int)); void *getline_cookie(char_u *(*fgetline)(int, void *, int, int), void *cookie); +char_u *getline_peek(char_u *(*fgetline)(int, void *, int, int), void *cookie); int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only); +void undo_cmdmod(exarg_T *eap, int save_msg_scroll); int parse_cmd_address(exarg_T *eap, char **errormsg, int silent); int checkforcmd(char_u **pp, char *cmd, int len); -char_u *find_ex_command(exarg_T *eap, int *full, void *((*lookup)(char_u *, size_t, cctx_T *)), cctx_T *cctx); +char_u *find_ex_command(exarg_T *eap, int *full, void *(*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx); int modifier_len(char_u *cmd); int cmd_exists(char_u *name); cmdidx_T excmd_get_cmdidx(char_u *cmd, int len); diff --git a/src/proto/highlight.pro b/src/proto/highlight.pro index 4a8ea3cca8..ca4498140c 100644 --- a/src/proto/highlight.pro +++ b/src/proto/highlight.pro @@ -43,19 +43,4 @@ void set_context_in_highlight_cmd(expand_T *xp, char_u *arg); char_u *get_highlight_name(expand_T *xp, int idx); char_u *get_highlight_name_ext(expand_T *xp, int idx, int skip_cleared); void free_highlight_fonts(void); -void clear_matches(win_T *wp); -void init_search_hl(win_T *wp, match_T *search_hl); -void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum); -int prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **line, match_T *search_hl, int *search_attr); -int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match_T *search_hl, int *has_match_conc, int *match_conc, int did_line_attr, int lcs_eol_one); -int get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol); -void get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr); -void f_clearmatches(typval_T *argvars, typval_T *rettv); -void f_getmatches(typval_T *argvars, typval_T *rettv); -void f_setmatches(typval_T *argvars, typval_T *rettv); -void f_matchadd(typval_T *argvars, typval_T *rettv); -void f_matchaddpos(typval_T *argvars, typval_T *rettv); -void f_matcharg(typval_T *argvars, typval_T *rettv); -void f_matchdelete(typval_T *argvars, typval_T *rettv); -void ex_match(exarg_T *eap); /* vim: set ft=c : */ diff --git a/src/proto/list.pro b/src/proto/list.pro index 07dd4e2b1d..53502ae723 100644 --- a/src/proto/list.pro +++ b/src/proto/list.pro @@ -39,7 +39,7 @@ void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2); char_u *list2string(typval_T *tv, int copyID, int restore_copyID); int list_join(garray_T *gap, list_T *l, char_u *sep, int echo_style, int restore_copyID, int copyID); void f_join(typval_T *argvars, typval_T *rettv); -int get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error); +int eval_list(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error); int write_list(FILE *fd, list_T *list, int binary); void init_static_list(staticList10_T *sl); void f_list2str(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/match.pro b/src/proto/match.pro new file mode 100644 index 0000000000..37c21da7a6 --- /dev/null +++ b/src/proto/match.pro @@ -0,0 +1,17 @@ +/* match.c */ +void clear_matches(win_T *wp); +void init_search_hl(win_T *wp, match_T *search_hl); +void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum); +int prepare_search_hl_line(win_T *wp, linenr_T lnum, colnr_T mincol, char_u **line, match_T *search_hl, int *search_attr); +int update_search_hl(win_T *wp, linenr_T lnum, colnr_T col, char_u **line, match_T *search_hl, int *has_match_conc, int *match_conc, int did_line_attr, int lcs_eol_one); +int get_prevcol_hl_flag(win_T *wp, match_T *search_hl, long curcol); +void get_search_match_hl(win_T *wp, match_T *search_hl, long col, int *char_attr); +void f_clearmatches(typval_T *argvars, typval_T *rettv); +void f_getmatches(typval_T *argvars, typval_T *rettv); +void f_setmatches(typval_T *argvars, typval_T *rettv); +void f_matchadd(typval_T *argvars, typval_T *rettv); +void f_matchaddpos(typval_T *argvars, typval_T *rettv); +void f_matcharg(typval_T *argvars, typval_T *rettv); +void f_matchdelete(typval_T *argvars, typval_T *rettv); +void ex_match(exarg_T *eap); +/* vim: set ft=c : */ diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro index e2a267141a..b5b8aae936 100644 --- a/src/proto/scriptfile.pro +++ b/src/proto/scriptfile.pro @@ -22,6 +22,7 @@ void ex_options(exarg_T *eap); linenr_T *source_breakpoint(void *cookie); int *source_dbg_tick(void *cookie); int source_level(void *cookie); +char_u *source_nextline(void *cookie); int do_source(char_u *fname, int check_other, int is_vimrc, int *ret_sid); void ex_scriptnames(exarg_T *eap); void scriptnames_slash_adjust(void); diff --git a/src/proto/typval.pro b/src/proto/typval.pro index 6eebde26e0..3bc2f2c5e5 100644 --- a/src/proto/typval.pro +++ b/src/proto/typval.pro @@ -4,18 +4,6 @@ typval_T *alloc_string_tv(char_u *s); void free_tv(typval_T *varp); void clear_tv(typval_T *varp); void init_tv(typval_T *varp); -int tv_check_lock(typval_T *tv, char_u *name, int use_gettext); -void copy_tv(typval_T *from, typval_T *to); -int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int ic); -char_u *typval_tostring(typval_T *arg); -int tv_islocked(typval_T *tv); -int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); -int get_option_tv(char_u **arg, typval_T *rettv, int evaluate); -int get_number_tv(char_u **arg, typval_T *rettv, int evaluate, int want_string); -int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); -int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); -char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); -int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); varnumber_T tv_get_number(typval_T *varp); varnumber_T tv_get_number_chk(typval_T *varp, int *denote); float_T tv_get_float(typval_T *varp); @@ -23,8 +11,20 @@ char_u *tv_get_string(typval_T *varp); char_u *tv_get_string_buf(typval_T *varp, char_u *buf); char_u *tv_get_string_chk(typval_T *varp); char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf); +char_u *tv_stringify(typval_T *varp, char_u *buf); +int tv_check_lock(typval_T *tv, char_u *name, int use_gettext); +void copy_tv(typval_T *from, typval_T *to); +int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int ic); +char_u *typval_tostring(typval_T *arg); +int tv_islocked(typval_T *tv); +int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); +int eval_option(char_u **arg, typval_T *rettv, int evaluate); +int eval_number(char_u **arg, typval_T *rettv, int evaluate, int want_string); +int eval_string(char_u **arg, typval_T *rettv, int evaluate); +int eval_lit_string(char_u **arg, typval_T *rettv, int evaluate); +char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); +int eval_env_var(char_u **arg, typval_T *rettv, int evaluate); linenr_T tv_get_lnum(typval_T *argvars); linenr_T tv_get_lnum_buf(typval_T *argvars, buf_T *buf); buf_T *tv_get_buf(typval_T *tv, int curtab_only); -char_u *tv_stringify(typval_T *varp, char_u *buf); /* vim: set ft=c : */ diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index 6ed79ba035..75a1562570 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -3,10 +3,11 @@ void func_init(void); hashtab_T *func_tbl_get(void); int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip, exarg_T *eap, char_u **line_to_free); char_u *get_lambda_name(void); -int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate); +char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state); +int get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg); 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); +int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, 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, int is_global, 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); diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro index 040e4d7eb7..05f6d50220 100644 --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -1,5 +1,5 @@ /* vim9compile.c */ -int check_defined(char_u *p, int len, cctx_T *cctx); +int check_defined(char_u *p, size_t len, cctx_T *cctx); type_T *typval2type(typval_T *tv); int check_type(type_T *expected, type_T *actual, int give_msg); char_u *skip_type(char_u *start); diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro index a11f6af7a5..6a32abdcac 100644 --- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -4,8 +4,8 @@ void ex_vim9script(exarg_T *eap); void ex_export(exarg_T *eap); void free_imports(int sid); void ex_import(exarg_T *eap); -int find_exported(int sid, char_u **argp, int *name_len, ufunc_T **ufunc, type_T **type); -char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx); +int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type); +char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx); char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg); int check_script_var_type(typval_T *dest, typval_T *value, char_u *name); /* vim: set ft=c : */ diff --git a/src/quickfix.c b/src/quickfix.c index ba54fab9c7..a7d211822a 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -7374,6 +7374,7 @@ qf_free_stack(win_T *wp, qf_info_T *qi) * Populate the quickfix list with the items supplied in the list * of dictionaries. "title" will be copied to w:quickfix_title. * "action" is 'a' for add, 'r' for replace. Otherwise create a new list. + * When "what" is not NULL then only set some properties. */ int set_errorlist( @@ -7400,6 +7401,14 @@ set_errorlist( return OK; } + // A dict argument cannot be specified with a non-empty list argument + if (list->lv_len != 0 && what != NULL) + { + semsg(_(e_invarg2), + _("cannot have both a list and a \"what\" argument")); + return FAIL; + } + incr_quickfix_busy(); if (what != NULL) @@ -7680,7 +7689,7 @@ ex_cexpr(exarg_T *eap) // Evaluate the expression. When the result is a string or a list we can // use it to fill the errorlist. - tv = eval_expr(eap->arg, &eap->nextcmd); + tv = eval_expr(eap->arg, eap); if (tv != NULL) { if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL) @@ -8098,7 +8107,7 @@ set_qf_ll_list( else { list_T *l = list_arg->vval.v_list; - dict_T *d = NULL; + dict_T *what = NULL; int valid_dict = TRUE; if (action_arg->v_type == VAR_STRING) @@ -8120,8 +8129,8 @@ set_qf_ll_list( if (action_arg->v_type != VAR_UNKNOWN && what_arg->v_type != VAR_UNKNOWN) { - if (what_arg->v_type == VAR_DICT) - d = what_arg->vval.v_dict; + if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL) + what = what_arg->vval.v_dict; else { emsg(_(e_dictreq)); @@ -8130,9 +8139,10 @@ set_qf_ll_list( } ++recursive; - if (l != NULL && action && valid_dict && set_errorlist(wp, l, action, + if (l != NULL && action && valid_dict + && set_errorlist(wp, l, action, (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"), - d) == OK) + what) == OK) rettv->vval.v_number = 0; --recursive; } diff --git a/src/regexp.c b/src/regexp.c index de0b0fad43..229f6ef2b7 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -2066,7 +2066,7 @@ vim_regsub_both( clear_tv(&rettv); } else - eval_result = eval_to_string(source + 2, NULL, TRUE); + eval_result = eval_to_string(source + 2, TRUE); if (eval_result != NULL) { diff --git a/src/register.c b/src/register.c index 49f7a7c86a..9d4354aff2 100644 --- a/src/register.c +++ b/src/register.c @@ -136,7 +136,7 @@ get_expr_line(void) return expr_copy; ++nested; - rv = eval_to_string(expr_copy, NULL, TRUE); + rv = eval_to_string(expr_copy, TRUE); --nested; vim_free(expr_copy); return rv; @@ -989,16 +989,16 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg) for (n = 0; n < reg->y_size; n++) list_append_string(list, reg->y_array[n], -1); list->lv_lock = VAR_FIXED; - dict_add_list(v_event, "regcontents", list); + (void)dict_add_list(v_event, "regcontents", list); buf[0] = (char_u)oap->regname; buf[1] = NUL; - dict_add_string(v_event, "regname", buf); + (void)dict_add_string(v_event, "regname", buf); buf[0] = get_op_char(oap->op_type); buf[1] = get_extra_op_char(oap->op_type); buf[2] = NUL; - dict_add_string(v_event, "operator", buf); + (void)dict_add_string(v_event, "operator", buf); buf[0] = NUL; buf[1] = NUL; @@ -1011,9 +1011,9 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg) reglen + 1); break; } - dict_add_string(v_event, "regtype", buf); + (void)dict_add_string(v_event, "regtype", buf); - dict_add_bool(v_event, "visual", oap->is_VIsual); + (void)dict_add_bool(v_event, "visual", oap->is_VIsual); // Lock the dictionary and its keys dict_set_items_ro(v_event); diff --git a/src/screen.c b/src/screen.c index 333df446b5..1c57bb193b 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1160,7 +1160,7 @@ get_keymap_str( curwin = wp; STRCPY(buf, "b:keymap_name"); // must be writable ++emsg_skip; - s = p = eval_to_string(buf, NULL, FALSE); + s = p = eval_to_string(buf, FALSE); --emsg_skip; curbuf = old_curbuf; curwin = old_curwin; diff --git a/src/scriptfile.c b/src/scriptfile.c index caeab19285..9ffc66c1b1 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1050,6 +1050,15 @@ source_level(void *cookie) { return ((struct source_cookie *)cookie)->level; } + +/* + * Return the readahead line. + */ + char_u * +source_nextline(void *cookie) +{ + return ((struct source_cookie *)cookie)->nextline; +} #endif #if (defined(MSWIN) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC) diff --git a/src/spellfile.c b/src/spellfile.c index d8cf3d4849..fc365e2a03 100644 --- a/src/spellfile.c +++ b/src/spellfile.c @@ -5908,7 +5908,8 @@ mkspell( spin.si_newcompID = 127; // start compound ID at first maximum // default: fnames[0] is output file, following are input files - innames = &fnames[1]; + // When "fcount" is 1 there is only one file. + innames = &fnames[fcount == 1 ? 0 : 1]; incount = fcount - 1; wfname = alloc(MAXPATHL); @@ -5922,14 +5923,12 @@ mkspell( { // For ":mkspell path/en.latin1.add" output file is // "path/en.latin1.add.spl". - innames = &fnames[0]; incount = 1; vim_snprintf((char *)wfname, MAXPATHL, "%s.spl", fnames[0]); } else if (fcount == 1) { // For ":mkspell path/vim" output file is "path/vim.latin1.spl". - innames = &fnames[0]; incount = 1; vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL, fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc()); diff --git a/src/spellsuggest.c b/src/spellsuggest.c index c03233f52e..0821dc62cb 100644 --- a/src/spellsuggest.c +++ b/src/spellsuggest.c @@ -676,8 +676,6 @@ spell_suggest(int count) mch_memmove(p, line, c); STRCPY(p + c, stp->st_word); STRCAT(p, sug.su_badptr + stp->st_orglen); - ml_replace(curwin->w_cursor.lnum, p, FALSE); - curwin->w_cursor.col = c; // For redo we use a change-word command. ResetRedobuff(); @@ -686,7 +684,10 @@ spell_suggest(int count) stp->st_wordlen + sug.su_badlen - stp->st_orglen); AppendCharToRedobuff(ESC); - // After this "p" may be invalid. + // "p" may be freed here + ml_replace(curwin->w_cursor.lnum, p, FALSE); + curwin->w_cursor.col = c; + changed_bytes(curwin->w_cursor.lnum, c); } } @@ -1405,7 +1406,8 @@ suggest_trie_walk( tword[sp->ts_twordlen] = NUL; if (sp->ts_prefixdepth <= PFD_NOTSPECIAL - && (sp->ts_flags & TSF_PREFIXOK) == 0) + && (sp->ts_flags & TSF_PREFIXOK) == 0 + && pbyts != NULL) { // There was a prefix before the word. Check that the prefix // can be used with this word. diff --git a/src/structs.h b/src/structs.h index 1d1d7e1893..c8f528afc2 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1529,6 +1529,9 @@ struct blobvar_S char bv_lock; // zero, VAR_LOCKED, VAR_FIXED }; +typedef int (*cfunc_T)(int argcount, typval_T *argvars, typval_T *rettv, void *state); +typedef void (*cfunc_free_T)(void *state); + #if defined(FEAT_EVAL) || defined(PROTO) typedef struct funccall_S funccall_T; @@ -1562,6 +1565,11 @@ typedef struct char_u *uf_va_name; // name from "...name" or NULL type_T *uf_va_type; // type from "...name: type" or NULL type_T *uf_func_type; // type of the function, &t_func_any if unknown +# if defined(FEAT_LUA) + cfunc_T uf_cb; // callback function for cfunc + cfunc_free_T uf_cb_free; // callback function to free cfunc + void *uf_cb_state; // state of uf_cb +# endif garray_T uf_lines; // function lines # ifdef FEAT_PROFILE @@ -1607,6 +1615,7 @@ typedef struct #define FC_EXPORT 0x100 // "export def Func()" #define FC_NOARGS 0x200 // no a: variables in lambda #define FC_VIM9 0x400 // defined in vim9 script file +#define FC_CFUNC 0x800 // defined as Lua C func #define MAX_FUNC_ARGS 20 // maximum number of function arguments #define VAR_SHORT_LEN 20 // short variable name length @@ -1746,6 +1755,29 @@ typedef struct # endif } scriptitem_T; +// Struct passed through eval() functions. +// See EVALARG_EVALUATE for a fixed value with eval_flags set to EVAL_EVALUATE. +typedef struct { + int eval_flags; // EVAL_ flag values below + int eval_break_count; // nr of line breaks consumed + + // copied from exarg_T when "getline" is "getsourceline". Can be NULL. + char_u *(*eval_getline)(int, void *, int, int); + void *eval_cookie; // argument for eval_getline() + + // Used to collect lines while parsing them, so that they can be + // concatenated later. Used when "eval_ga.ga_itemsize" is not zero. + // "eval_ga.ga_data" is a list of pointers to lines. + garray_T eval_ga; + + // pointer to the line obtained with getsourceline() + char_u *eval_tofree; +} evalarg_T; + +// Flags for expression evaluation. +#define EVAL_EVALUATE 1 // when missing don't actually evaluate +#define EVAL_CONSTANT 2 // when not a constant return FAIL + # ifdef FEAT_PROFILE /* * Struct used in sn_prl_ga for every line of a script. @@ -1781,6 +1813,10 @@ typedef struct { int dummy; } scriptitem_T; +typedef struct +{ + int dummy; +} evalarg_T; #endif // Struct passed between functions dealing with function call execution. diff --git a/src/terminal.c b/src/terminal.c index 729f345683..0ab40fa859 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -1394,8 +1394,8 @@ term_convert_key(term_T *term, int c, int modmask, char *buf) case K_MOUSEUP: other = term_send_mouse(vterm, 5, 1); break; case K_MOUSEDOWN: other = term_send_mouse(vterm, 4, 1); break; - case K_MOUSELEFT: /* TODO */ return 0; - case K_MOUSERIGHT: /* TODO */ return 0; + case K_MOUSELEFT: other = term_send_mouse(vterm, 7, 1); break; + case K_MOUSERIGHT: other = term_send_mouse(vterm, 6, 1); break; case K_LEFTMOUSE: case K_LEFTMOUSE_NM: @@ -2479,6 +2479,8 @@ terminal_loop(int blocking) restore_cursor = TRUE; raw_c = term_vgetc(); +if (raw_c > 0) + ch_log(NULL, "terminal_loop() got %d", raw_c); if (!term_use_loop_check(TRUE) || in_terminal_loop != curbuf->b_term) { // Job finished while waiting for a character. Push back the diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 0fb80dfb2f..34ad0baee9 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -20,16 +20,12 @@ SCRIPTS_ALL = \ # Tests that run on most systems, but not on Amiga. SCRIPTS_MORE1 = \ - test52.out \ - test86.out \ - test87.out - + test52.out # Tests that run on most systems, but not on Amiga and DOS/Windows. SCRIPTS_MORE2 = \ test49.out - # Tests that run on most systems, but not on VMS SCRIPTS_MORE4 = \ test59.out @@ -37,7 +33,6 @@ SCRIPTS_MORE4 = \ # Tests specifically for MS-Windows. SCRIPTS_WIN32 = - # Tests for the GUI. SCRIPTS_GUI = @@ -90,6 +85,7 @@ NEW_TESTS = \ test_close_count \ test_cmdline \ test_command_count \ + test_comments \ test_comparators \ test_compiler \ test_conceal \ @@ -276,6 +272,7 @@ NEW_TESTS = \ test_termcodes \ test_termencoding \ test_terminal \ + test_terminal2 \ test_terminal_fail \ test_textformat \ test_textobjects \ @@ -309,7 +306,6 @@ NEW_TESTS = \ test_alot_utf8 \ test_alot - # Test targets that use runtest.vim. # Keep test_alot*.res as the last one, sort the others. # test_largefile.res is omitted, it uses too much resources to run on CI. @@ -342,6 +338,7 @@ NEW_TESTS_RES = \ test_close_count.res \ test_cmdline.res \ test_command_count.res \ + test_comments.res \ test_comparators.res \ test_conceal.res \ test_const.res \ @@ -492,6 +489,7 @@ NEW_TESTS_RES = \ test_termcodes.res \ test_termencoding.res \ test_terminal.res \ + test_terminal2.res \ test_terminal_fail.res \ test_textformat.res \ test_textobjects.res \ diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms index a89bb244fd..991a2f773b 100644 --- a/src/testdir/Make_vms.mms +++ b/src/testdir/Make_vms.mms @@ -4,7 +4,7 @@ # Authors: Zoltan Arpadffy, # Sandor Kopanyi, # -# Last change: 2019 May 31 +# Last change: 2020 Jul 03 # # This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64. # Edit the lines in the Configuration section below to select. @@ -115,10 +115,6 @@ SCRIPT_ODS5 = test102.out SCRIPT_GDIFF = test47.out .ENDIF -.IFDEF HAVE_PYTHON -SCRIPT_PYTHON = test86.out test87.out -.ENDIF - .in.out : -@ !clean up before doing the test -@ if "''F$SEARCH("test.out.*")'" .NES. "" then delete/noconfirm/nolog test.out.* @@ -140,7 +136,7 @@ SCRIPT_PYTHON = test86.out test87.out -@ if "''F$SEARCH("Xtest.*")'" .NES. "" then delete/noconfirm/nolog Xtest.*.* all : clean nolog $(START_WITH) $(SCRIPT) $(SCRIPT_GUI) $(SCRIPT_UNIX) $(SCRIPT_WIN) $(SCRIPT_SPELL) $(SCRIPT_ODS5) \ - $(SCRIPT_GDIFF) $(SCRIPT_MZSCH) $(SCRIPT_LUA) $(SCRIPT_PYTHON) nolog + $(SCRIPT_GDIFF) $(SCRIPT_MZSCH) $(SCRIPT_LUA) nolog -@ write sys$output " " -@ write sys$output "-----------------------------------------------" -@ write sys$output " All done" diff --git a/src/testdir/Makefile b/src/testdir/Makefile index 29efa0fe0e..7f9ef04342 100644 --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -168,14 +168,6 @@ newtestssilent: $(NEW_TESTS_RES) $(RUN_VIMTEST) $(NO_INITS) -S runtest.vim $*.vim $(REDIR_TEST_TO_NULL) @rm vimcmd -# Temporary: Do not use $REDIR_TEST_TO_NULL for test_terminal to be able to see -# where it sometimes hanges on CI. -test_terminal.res: test_terminal.vim - @echo "$(VIMPROG)" > vimcmd - @echo "$(RUN_VIMTEST)" >> vimcmd - $(RUN_VIMTEST) $(NO_INITS) -S runtest.vim $*.vim - @rm vimcmd - test_gui.res: test_gui.vim @echo "$(VIMPROG)" > vimcmd @echo "$(RUN_GVIMTEST)" >> vimcmd diff --git a/src/testdir/dumps/Test_diff_syntax_1.dump b/src/testdir/dumps/Test_diff_syntax_1.dump index 05598ff096..9204b47ab9 100644 --- a/src/testdir/dumps/Test_diff_syntax_1.dump +++ b/src/testdir/dumps/Test_diff_syntax_1.dump @@ -17,4 +17,4 @@ |~| @73 |~| @73 |X+1#0000000&|p|r|o|g|r|a|m|1|.|c| @45|1|,|1| @11|A|l@1 -|"+0&&|X|p|r|o|g|r|a|m|2|.|c|"| |5|L|,| |7|6|C| @53 +|"+0&&|X|p|r|o|g|r|a|m|2|.|c|"| |5|L|,| |7|6|B| @53 diff --git a/src/testdir/dumps/Test_display_unprintable_01.dump b/src/testdir/dumps/Test_display_unprintable_01.dump index e4cc0d9c7f..552b40213e 100644 --- a/src/testdir/dumps/Test_display_unprintable_01.dump +++ b/src/testdir/dumps/Test_display_unprintable_01.dump @@ -6,4 +6,4 @@ |t|w|o| @46 |~+0#4040ff13&| @48 |X+1#0000000&|u|n|i|x|.|t|x|t| @22|1|,|1| @11|A|l@1 -|"+0&&|X|m|a|c|.|t|x|t|"| |[|n|o|e|o|l|]|[|m|a|c|]| |2|L|,| |9|C| @19 +|"+0&&|X|m|a|c|.|t|x|t|"| |[|n|o|e|o|l|]|[|m|a|c|]| |2|L|,| |9|B| @19 diff --git a/src/testdir/dumps/Test_long_file_name_1.dump b/src/testdir/dumps/Test_long_file_name_1.dump index 46fa9bdfbe..1dcafc315c 100644 --- a/src/testdir/dumps/Test_long_file_name_1.dump +++ b/src/testdir/dumps/Test_long_file_name_1.dump @@ -5,4 +5,4 @@ |~| @73 |~| @73 |~| @73 -|<+0#0000000&|x@64|"| |0|L|,| |0|C| +|<+0#0000000&|x@64|"| |0|L|,| |0|B| diff --git a/src/testdir/dumps/Test_tselect_1.dump b/src/testdir/dumps/Test_tselect_1.dump index cdaee45776..909012245e 100644 --- a/src/testdir/dumps/Test_tselect_1.dump +++ b/src/testdir/dumps/Test_tselect_1.dump @@ -7,4 +7,4 @@ |~| @48 |~| @48 |~| @48 -|"+0#0000000&|X|t|e|s|t|.|c|"| |2|L|,| |2|3|C| @14|1|,|1| @10|A|l@1| +|"+0#0000000&|X|t|e|s|t|.|c|"| |2|L|,| |2|3|B| @14|1|,|1| @10|A|l@1| diff --git a/src/testdir/dumps/Test_vim9_silent_echo.dump b/src/testdir/dumps/Test_vim9_silent_echo.dump new file mode 100644 index 0000000000..f5f7927859 --- /dev/null +++ b/src/testdir/dumps/Test_vim9_silent_echo.dump @@ -0,0 +1,6 @@ +| +0&#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @73 +|:+0#0000000&|a|b|c> @70 diff --git a/src/testdir/mouse.vim b/src/testdir/mouse.vim index a28a439c19..5eab1de48f 100644 --- a/src/testdir/mouse.vim +++ b/src/testdir/mouse.vim @@ -169,4 +169,20 @@ func MouseWheelDown(row, col) call feedkeys(MouseWheelDownCode(a:row, a:col), 'Lx!') endfunc +func MouseWheelLeftCode(row, col) + return TerminalEscapeCode(0x42, a:row, a:col, 'M') +endfunc + +func MouseWheelLeft(row, col) + call feedkeys(MouseWheelLeftCode(a:row, a:col), 'Lx!') +endfunc + +func MouseWheelRightCode(row, col) + return TerminalEscapeCode(0x43, a:row, a:col, 'M') +endfunc + +func MouseWheelRight(row, col) + call feedkeys(MouseWheelRightCode(a:row, a:col), 'Lx!') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim index 3e0929c349..bbd28be1cc 100644 --- a/src/testdir/shared.vim +++ b/src/testdir/shared.vim @@ -353,4 +353,19 @@ func GetMessages() return msg_list endfunc +" Run the list of commands in 'cmds' and look for 'errstr' in exception. +" Note that assert_fails() cannot be used in some places and this function +" can be used. +func AssertException(cmds, errstr) + let save_exception = '' + try + for cmd in a:cmds + exe cmd + endfor + catch + let save_exception = v:exception + endtry + call assert_match(a:errstr, save_exception) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/term_util.vim b/src/testdir/term_util.vim index 7a73adbe07..17f9752a99 100644 --- a/src/testdir/term_util.vim +++ b/src/testdir/term_util.vim @@ -146,4 +146,28 @@ func StopVimInTerminal(buf) only! endfunc +" Open a terminal with a shell, assign the job to g:job and return the buffer +" number. +func Run_shell_in_terminal(options) + if has('win32') + let buf = term_start([&shell,'/k'], a:options) + else + let buf = term_start(&shell, a:options) + endif + let g:test_is_flaky = 1 + + let termlist = term_list() + call assert_equal(1, len(termlist)) + call assert_equal(buf, termlist[0]) + + let g:job = term_getjob(buf) + call assert_equal(v:t_job, type(g:job)) + + let string = string({'job': buf->term_getjob()}) + call assert_match("{'job': 'process \\d\\+ run'}", string) + + return buf +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test86.in b/src/testdir/test86.in deleted file mode 100644 index e24c13d1ca..0000000000 --- a/src/testdir/test86.in +++ /dev/null @@ -1,1711 +0,0 @@ -Tests for various python features. vim: set ft=vim : - -NOTE: This will cause errors when run under valgrind. -This would require recompiling Python with: - ./configure --without-pymalloc -See http://svn.python.org/view/python/trunk/Misc/README.valgrind?view=markup - -STARTTEST -:so small.vim -:set encoding=latin1 -:set noswapfile -:if !has('python') || !has('quickfix') | e! test.ok | wq! test.out | endif -:lang C -:fun Test() -:py import vim -:py cb = vim.current.buffer -:let l = [] -:py l=vim.bindeval('l') -:py f=vim.bindeval('function("strlen")') -:" Extending List directly with different types -:py l.extend([1, "as'd", [1, 2, f, {'a': 1}]]) -:$put =string(l) -:$put =string(l[-1]) -:try -: $put =string(l[-4]) -:catch -: $put =v:exception[:13] -:endtry -:" List assignment -:py l[0]=0 -:$put =string(l) -:py l[-2]=f -:$put =string(l) -:" -:" Extending Dictionary directly with different types -:let d = {} -:fun d.f() -: return 1 -:endfun -py << trim EOF - d=vim.bindeval('d') - d['1']='asd' - d.update() # Must not do anything, including throwing errors - d.update(b=[1, 2, f]) - d.update((('-1', {'a': 1}),)) - d.update({'0': -1}) - dk = d.keys() - dv = d.values() - di = d.items() - cmpfun = lambda a, b: cmp(repr(a), repr(b)) - dk.sort(cmpfun) - dv.sort(cmpfun) - di.sort(cmpfun) -EOF -:$put =pyeval('d[''f''](self={})') -:$put =pyeval('repr(dk)') -:$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g') -:$put =substitute(pyeval('repr(di)'),'0x\x\+','','g') -:for [key, Val] in sort(items(d)) -: $put =string(key) . ' : ' . string(Val) -: unlet key Val -:endfor -:py del dk -:py del di -:py del dv -:" -:" removing items with del -:py del l[2] -:$put =string(l) -:let l = range(8) -:py l=vim.bindeval('l') -:try -: py del l[:3] -: py del l[1:] -:catch -: $put =v:exception -:endtry -:$put =string(l) -:" -:py del d['-1'] -:py del d['f'] -:$put =string(pyeval('d.get(''b'', 1)')) -:$put =string(pyeval('d.pop(''b'')')) -:$put =string(pyeval('d.get(''b'', 1)')) -:$put =string(pyeval('d.pop(''1'', 2)')) -:$put =string(pyeval('d.pop(''1'', 2)')) -:$put =pyeval('repr(d.has_key(''0''))') -:$put =pyeval('repr(d.has_key(''1''))') -:$put =pyeval('repr(''0'' in d)') -:$put =pyeval('repr(''1'' in d)') -:$put =pyeval('repr(list(iter(d)))') -:$put =string(d) -:$put =pyeval('repr(d.popitem())') -:$put =pyeval('repr(d.get(''0''))') -:$put =pyeval('repr(list(iter(d)))') -:" -:" removing items out of range: silently skip items that don't exist -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:" The following two ranges delete nothing as they match empty list: -:py del l[2:1] -:$put =string(l) -:py del l[2:2] -:$put =string(l) -:py del l[2:3] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[2:4] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[2:5] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[2:6] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:" The following two ranges delete nothing as they match empty list: -:py del l[-1:2] -:$put =string(l) -:py del l[-2:2] -:$put =string(l) -:py del l[-3:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[-4:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[-5:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[-6:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[::2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[3:0:-2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py del l[2:4:-2] -:$put =string(l) -:" -:" Slice assignment to a list -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py l[0:0]=['a'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py l[1:2]=['b'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py l[2:4]=['c'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py l[4:4]=['d'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py l[-1:2]=['e'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py l[-10:2]=['f'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:py l[2:-10]=['g'] -:$put =string(l) -:let l = [] -:py l=vim.bindeval('l') -:py l[0:0]=['h'] -:$put =string(l) -:let l = range(8) -:py l=vim.bindeval('l') -:py l[2:6:2] = [10, 20] -:$put =string(l) -:let l = range(8) -:py l=vim.bindeval('l') -:py l[6:2:-2] = [10, 20] -:$put =string(l) -:let l = range(8) -:py l=vim.bindeval('l') -:py l[6:2] = () -:$put =string(l) -:let l = range(8) -:py l=vim.bindeval('l') -:py l[6:2:1] = () -:$put =string(l) -:let l = range(8) -:py l=vim.bindeval('l') -:py l[2:2:1] = () -:$put =string(l) -:" -:" Locked variables -:let l = [0, 1, 2, 3] -:py l=vim.bindeval('l') -:lockvar! l -py << trim EOF - def emsg(ei): - return ei[0].__name__ + ':' + repr(ei[1].args) - - try: - l[2]='i' - except vim.error: - cb.append('l[2] threw vim.error: ' + emsg(sys.exc_info())) -EOF -:$put =string(l) -:unlockvar! l -:" -:" Function calls -py << trim EOF - import sys - def ee(expr, g=globals(), l=locals()): - try: - exec(expr, g, l) - except: - ei = sys.exc_info() - msg = emsg(ei) - msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'') - if expr.find('None') > -1: - msg = msg.replace('TypeError:(\'iteration over non-sequence\',)', - 'TypeError:("\'NoneType\' object is not iterable",)') - if expr.find('FailingNumber') > -1: - msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'') - msg = msg.replace('TypeError:(\'iteration over non-sequence\',)', - 'TypeError:("\'FailingNumber\' object is not iterable",)') - if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1: - msg = msg.replace('(\'', '("').replace('\',)', '",)') - # Some Python versions say can't, others cannot. - if msg.find('can\'t') > -1: - msg = msg.replace('can\'t', 'cannot') - # Some Python versions use single quote, some double quote - if msg.find('"cannot ') > -1: - msg = msg.replace('"cannot ', '\'cannot ') - if msg.find(' attributes"') > -1: - msg = msg.replace(' attributes"', ' attributes\'') - if expr == 'fd(self=[])': - # HACK: PyMapping_Check changed meaning - msg = msg.replace('AttributeError:(\'keys\',)', - 'TypeError:(\'unable to convert list to vim dictionary\',)') - vim.current.buffer.append(expr + ':' + msg) - else: - vim.current.buffer.append(expr + ':NOT FAILED') -EOF -:fun New(...) -: return ['NewStart']+a:000+['NewEnd'] -:endfun -:fun DictNew(...) dict -: return ['DictNewStart']+a:000+['DictNewEnd', self] -:endfun -:let l=[function('New'), function('DictNew')] -:py l=vim.bindeval('l') -:py l.extend(list(l[0](1, 2, 3))) -:$put =string(l) -:py l.extend(list(l[1](1, 2, 3, self={'a': 'b'}))) -:$put =string(l) -:py l.extend([l[0].name]) -:$put =string(l) -:py ee('l[1](1, 2, 3)') -:py f=l[0] -:delfunction New -:py ee('f(1, 2, 3)') -:if has('float') -: let l=[0.0] -: py l=vim.bindeval('l') -: py l.extend([0.0]) -: $put =string(l) -:else -: $put ='[0.0, 0.0]' -:endif -:let messages=[] -:delfunction DictNew -py << trim EOF - d=vim.bindeval('{}') - m=vim.bindeval('messages') - def em(expr, g=globals(), l=locals()): - try: - exec(expr, g, l) - except: - m.extend([sys.exc_type.__name__]) - - em('d["abc1"]') - em('d["abc1"]="\\0"') - em('d["abc1"]=vim') - em('d[""]=1') - em('d["a\\0b"]=1') - em('d[u"a\\0b"]=1') - - em('d.pop("abc1")') - em('d.popitem()') - del em - del m -EOF -:$put =messages -:unlet messages -:" locked and scope attributes -:let d={} | let dl={} | lockvar dl -:for s in split("d dl v: g:") -: let name=tr(s, ':', 's') -: execute 'py '.name.'=vim.bindeval("'.s.'")' -: let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".pyeval(name.".".v:val)'), ';') -: $put =toput -:endfor -:silent! let d.abc2=1 -:silent! let dl.abc3=1 -:py d.locked=True -:py dl.locked=False -:silent! let d.def=1 -:silent! let dl.def=1 -:put ='d:'.string(d) -:put ='dl:'.string(dl) -:unlet d dl -: -:let l=[] | let ll=[] | lockvar ll -:for s in split("l ll") -: let name=tr(s, ':', 's') -: execute 'py '.name.'=vim.bindeval("'.s.'")' -: let toput=s.' : locked:'.pyeval(name.'.locked') -: $put =toput -:endfor -:silent! call extend(l, [0]) -:silent! call extend(ll, [0]) -:py l.locked=True -:py ll.locked=False -:silent! call extend(l, [1]) -:silent! call extend(ll, [1]) -:put ='l:'.string(l) -:put ='ll:'.string(ll) -:unlet l ll -:" -:" pyeval() -:let l=pyeval('range(3)') -:$put =string(l) -:let d=pyeval('{"a": "b", "c": 1, "d": ["e"]}') -:$put =sort(items(d)) -:let v:errmsg = '' -:$put ='pyeval(\"None\") = ' . pyeval('None') . v:errmsg -:if has('float') -: let f=pyeval('0.0') -: $put =string(f) -:else -: $put ='0.0' -:endif -:" Invalid values: -:for e in ['"\0"', '{"\0": 1}', 'undefined_name', 'vim'] -: try -: let v=pyeval(e) -: catch -: let toput=e.":\t".v:exception[:13] -: $put =toput -: endtry -:endfor -:" -:" threading -:let l = [0] -:py l=vim.bindeval('l') -py << trim EOF - import threading - import time - - class T(threading.Thread): - def __init__(self): - threading.Thread.__init__(self) - self.t = 0 - self.running = True - - def run(self): - while self.running: - self.t += 1 - time.sleep(0.1) - - t = T() - del T - t.start() -EOF -:sleep 1 -:py t.running = False -:py t.join() -:" Check if the background thread is working. Count should be 10, but on a -:" busy system (AppVeyor) it can be much lower. -:py l[0] = t.t > 4 -:py del time -:py del threading -:py del t -:$put =string(l) -:" -:" settrace -:let l = [] -:py l=vim.bindeval('l') -py << trim EOF - import sys - - def traceit(frame, event, arg): - global l - if event == "line": - l.extend([frame.f_lineno]) - return traceit - - def trace_main(): - for i in range(5): - pass -EOF -:py sys.settrace(traceit) -:py trace_main() -:py sys.settrace(None) -:py del traceit -:py del trace_main -:$put =string(l) -:" -:" Slice -:py ll = vim.bindeval('[0, 1, 2, 3, 4, 5]') -:py l = ll[:4] -:$put =string(pyeval('l')) -:py l = ll[2:] -:$put =string(pyeval('l')) -:py l = ll[:-4] -:$put =string(pyeval('l')) -:py l = ll[-2:] -:$put =string(pyeval('l')) -:py l = ll[2:4] -:$put =string(pyeval('l')) -:py l = ll[4:2] -:$put =string(pyeval('l')) -:py l = ll[-4:-2] -:$put =string(pyeval('l')) -:py l = ll[-2:-4] -:$put =string(pyeval('l')) -:py l = ll[:] -:$put =string(pyeval('l')) -:py l = ll[0:6] -:$put =string(pyeval('l')) -:py l = ll[-10:10] -:$put =string(pyeval('l')) -:py l = ll[4:2:-1] -:$put =string(pyeval('l')) -:py l = ll[::2] -:$put =string(pyeval('l')) -:py l = ll[4:2:1] -:$put =string(pyeval('l')) -:py del l -:" -:" Vars -:let g:foo = 'bac' -:let w:abc3 = 'def' -:let b:baz = 'bar' -:let t:bar = 'jkl' -:try -: throw "Abc" -:catch -: put =pyeval('vim.vvars[''exception'']') -:endtry -:put =pyeval('vim.vars[''foo'']') -:put =pyeval('vim.current.window.vars[''abc3'']') -:put =pyeval('vim.current.buffer.vars[''baz'']') -:put =pyeval('vim.current.tabpage.vars[''bar'']') -:" -:" Options -:" paste: boolean, global -:" previewheight number, global -:" operatorfunc: string, global -:" number: boolean, window-local -:" numberwidth: number, window-local -:" colorcolumn: string, window-local -:" statusline: string, window-local/global -:" autoindent: boolean, buffer-local -:" shiftwidth: number, buffer-local -:" omnifunc: string, buffer-local -:" preserveindent: boolean, buffer-local/global -:" path: string, buffer-local/global -:let g:bufs=[bufnr('%')] -:new -:let g:bufs+=[bufnr('%')] -:vnew -:let g:bufs+=[bufnr('%')] -:wincmd j -:vnew -:let g:bufs+=[bufnr('%')] -:wincmd l -:fun RecVars(opt) -: let gval =string(eval('&g:'.a:opt)) -: let wvals=join(map(range(1, 4), 'v:val.":".string(getwinvar(v:val, "&".a:opt))')) -: let bvals=join(map(copy(g:bufs), 'v:val.":".string(getbufvar(v:val, "&".a:opt))')) -: put =' G: '.gval -: put =' W: '.wvals -: put =' B: '.wvals -:endfun -py << trim EOF - def e(s, g=globals(), l=locals()): - try: - exec(s, g, l) - except: - vim.command('return ' + repr(sys.exc_type.__name__)) - - def ev(s, g=globals(), l=locals()): - try: - return eval(s, g, l) - except: - vim.command('let exc=' + repr(sys.exc_type.__name__)) - return 0 -EOF -:fun E(s) -: python e(vim.eval('a:s')) -:endfun -:fun Ev(s) -: let r=pyeval('ev(vim.eval("a:s"))') -: if exists('exc') -: throw exc -: endif -: return r -:endfun -:py gopts1=vim.options -:py wopts1=vim.windows[2].options -:py wopts2=vim.windows[0].options -:py wopts3=vim.windows[1].options -:py bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options -:py bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options -:py bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options -:$put ='wopts iters equal: '.pyeval('list(wopts1) == list(wopts2)') -:$put ='bopts iters equal: '.pyeval('list(bopts1) == list(bopts2)') -:py gset=set(iter(gopts1)) -:py wset=set(iter(wopts1)) -:py bset=set(iter(bopts1)) -:set path=.,..,, -:let lst=[] -:let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]] -:let lst+=[['previewheight', 5, 1, 6, 'a', 0, 1, 0 ]] -:let lst+=[['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0 ]] -:let lst+=[['number', 0, 1, 1, 0, 1, 0, 1 ]] -:let lst+=[['numberwidth', 2, 3, 5, -100, 0, 0, 1 ]] -:let lst+=[['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1 ]] -:let lst+=[['statusline', '1', '2', '4', 0, 0, 1, 1 ]] -:let lst+=[['autoindent', 0, 1, 1, 2, 1, 0, 2 ]] -:let lst+=[['shiftwidth', 0, 2, 1, 3, 0, 0, 2 ]] -:let lst+=[['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2 ]] -:let lst+=[['preserveindent', 0, 1, 1, 2, 1, 1, 2 ]] -:let lst+=[['path', '.,,', ',,', '.', 0, 0, 1, 2 ]] -:for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst -: py oname=vim.eval('oname') -: py oval1=vim.bindeval('oval1') -: py oval2=vim.bindeval('oval2') -: py oval3=vim.bindeval('oval3') -: if invval is 0 || invval is 1 -: py invval=bool(vim.bindeval('invval')) -: else -: py invval=vim.bindeval('invval') -: endif -: if bool -: py oval1=bool(oval1) -: py oval2=bool(oval2) -: py oval3=bool(oval3) -: endif -: put ='>>> '.oname -: $put =' g/w/b:'.pyeval('oname in gset').'/'.pyeval('oname in wset').'/'.pyeval('oname in bset') -: $put =' g/w/b (in):'.pyeval('oname in gopts1').'/'.pyeval('oname in wopts1').'/'.pyeval('oname in bopts1') -: for v in ['gopts1', 'wopts1', 'bopts1'] -: try -: put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])') -: catch -: put =' p/'.v.'! '.v:exception -: endtry -: let r=E(v.'['''.oname.''']=invval') -: if r isnot 0 -: put =' inv: '.string(invval).'! '.r -: endif -: for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3']) -: let val=substitute(vv, '^.opts', 'oval', '') -: let r=E(vv.'['''.oname.''']='.val) -: if r isnot 0 -: put =' '.vv.'! '.r -: endif -: endfor -: endfor -: call RecVars(oname) -: for v in ['wopts3', 'bopts3'] -: let r=E('del '.v.'["'.oname.'"]') -: if r isnot 0 -: put =' del '.v.'! '.r -: endif -: endfor -: call RecVars(oname) -:endfor -:delfunction RecVars -:delfunction E -:delfunction Ev -:py del ev -:py del e -:only -:for buf in g:bufs[1:] -: execute 'bwipeout!' buf -:endfor -:py del gopts1 -:py del wopts1 -:py del wopts2 -:py del wopts3 -:py del bopts1 -:py del bopts2 -:py del bopts3 -:py del oval1 -:py del oval2 -:py del oval3 -:py del oname -:py del invval -:" -:" Test buffer object -:vnew -:put ='First line' -:put ='Second line' -:put ='Third line' -:1 delete _ -:py b=vim.current.buffer -:wincmd w -:mark a -:augroup BUFS -: autocmd BufFilePost * python cb.append(vim.eval('expand("")') + ':BufFilePost:' + vim.eval('bufnr("%")')) -: autocmd BufFilePre * python cb.append(vim.eval('expand("")') + ':BufFilePre:' + vim.eval('bufnr("%")')) -:augroup END -py << trim EOF - # Tests BufferAppend and BufferItem - cb.append(b[0]) - # Tests BufferSlice and BufferAssSlice - cb.append('abc5') # Will be overwritten - cb[-1:] = b[:-2] - # Test BufferLength and BufferAssSlice - cb.append('def') # Will not be overwritten - cb[len(cb):] = b[:] - # Test BufferAssItem and BufferMark - cb.append('ghi') # Will be overwritten - cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1])) - # Test BufferRepr - cb.append(repr(cb) + repr(b)) - # Modify foreign buffer - b.append('foo') - b[0]='bar' - b[0:0]=['baz'] - vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number) - # Test assigning to name property - import os - old_name = cb.name - cb.name = 'foo' - cb.append(cb.name[-11:].replace(os.path.sep, '/')) - b.name = 'bar' - cb.append(b.name[-11:].replace(os.path.sep, '/')) - cb.name = old_name - cb.append(cb.name[-17:].replace(os.path.sep, '/')) - del old_name - # Test CheckBuffer - for _b in vim.buffers: - if _b is not cb: - vim.command('bwipeout! ' + str(_b.number)) - del _b - cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid))) - for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")', 'b.name = "!"'): - try: - exec(expr) - except vim.error: - pass - else: - # Usually a SEGV here - # Should not happen in any case - cb.append('No exception for ' + expr) - vim.command('cd .') - del b -EOF -:augroup BUFS -: autocmd! -:augroup END -:augroup! BUFS -:" -:" Test vim.buffers object -:set hidden -:edit a -:buffer # -:edit b -:buffer # -:edit c -:buffer # -py << trim EOF - try: - from __builtin__ import next - except ImportError: - next = lambda o: o.next() - # Check GCing iterator that was not fully exhausted - i = iter(vim.buffers) - cb.append('i:' + str(next(i))) - # and also check creating more than one iterator at a time - i2 = iter(vim.buffers) - cb.append('i2:' + str(next(i2))) - cb.append('i:' + str(next(i))) - # The following should trigger GC and not cause any problems - del i - del i2 - i3 = iter(vim.buffers) - cb.append('i3:' + str(next(i3))) - del i3 - - prevnum = 0 - for b in vim.buffers: - # Check buffer order - if prevnum >= b.number: - cb.append('!!! Buffer numbers not in strictly ascending order') - # Check indexing: vim.buffers[number].number == number - cb.append(str(b.number) + ':' + repr(vim.buffers[b.number]) + '=' + repr(b)) - prevnum = b.number - del prevnum - - cb.append(str(len(vim.buffers))) - - bnums = list(map(lambda b: b.number, vim.buffers))[1:] - - # Test wiping out buffer with existing iterator - i4 = iter(vim.buffers) - cb.append('i4:' + str(next(i4))) - vim.command('bwipeout! ' + str(bnums.pop(0))) - try: - next(i4) - except vim.error: - pass - else: - cb.append('!!!! No vim.error') - i4 = iter(vim.buffers) - vim.command('bwipeout! ' + str(bnums.pop(-1))) - vim.command('bwipeout! ' + str(bnums.pop(-1))) - cb.append('i4:' + str(next(i4))) - try: - next(i4) - except StopIteration: - cb.append('StopIteration') - del i4 - del bnums -EOF -:" -:" Test vim.{tabpage,window}list and vim.{tabpage,window} objects -:tabnew 0 -:tabnew 1 -:vnew a.1 -:tabnew 2 -:vnew a.2 -:vnew b.2 -:vnew c.2 -py << trim EOF - cb.append('Number of tabs: ' + str(len(vim.tabpages))) - cb.append('Current tab pages:') - def W(w): - if repr(w).find('(unknown)') != -1: - return '' - else: - return repr(w) - - start = len(cb) - - def Cursor(w): - if w.buffer is cb: - return repr((start - w.cursor[0], w.cursor[1])) - else: - return repr(w.cursor) - - for t in vim.tabpages: - cb.append(' ' + repr(t) + '(' + str(t.number) + ')' + ': ' + str(len(t.windows)) + ' windows, current is ' + W(t.window)) - cb.append(' Windows:') - for w in t.windows: - cb.append(' ' + W(w) + '(' + str(w.number) + ')' + ': displays buffer ' + repr(w.buffer) + '; cursor is at ' + Cursor(w)) - # Other values depend on the size of the terminal, so they are checked partly: - for attr in ('height', 'row', 'width', 'col'): - try: - aval = getattr(w, attr) - if type(aval) is not long: - raise TypeError - if aval < 0: - raise ValueError - except Exception: - cb.append('!!!!!! Error while getting attribute ' + attr + ': ' + sys.exc_type.__name__) - del aval - del attr - w.cursor = (len(w.buffer), 0) - del W - del Cursor - cb.append('Number of windows in current tab page: ' + str(len(vim.windows))) - if list(vim.windows) != list(vim.current.tabpage.windows): - cb.append('!!!!!! Windows differ') -EOF -:" -:" Test vim.current -py << trim EOF - def H(o): - return repr(o) - cb.append('Current tab page: ' + repr(vim.current.tabpage)) - cb.append('Current window: ' + repr(vim.current.window) + ': ' + H(vim.current.window) + ' is ' + H(vim.current.tabpage.window)) - cb.append('Current buffer: ' + repr(vim.current.buffer) + ': ' + H(vim.current.buffer) + ' is ' + H(vim.current.window.buffer)+ ' is ' + H(vim.current.tabpage.window.buffer)) - del H - # Assigning: fails - try: - vim.current.window = vim.tabpages[0].window - except ValueError: - cb.append('ValueError at assigning foreign tab window') - - for attr in ('window', 'tabpage', 'buffer'): - try: - setattr(vim.current, attr, None) - except TypeError: - cb.append('Type error at assigning None to vim.current.' + attr) - del attr - - # Assigning: success - vim.current.tabpage = vim.tabpages[-2] - vim.current.buffer = cb - vim.current.window = vim.windows[0] - vim.current.window.cursor = (len(vim.current.buffer), 0) - cb.append('Current tab page: ' + repr(vim.current.tabpage)) - cb.append('Current window: ' + repr(vim.current.window)) - cb.append('Current buffer: ' + repr(vim.current.buffer)) - cb.append('Current line: ' + repr(vim.current.line)) - ws = list(vim.windows) - ts = list(vim.tabpages) - for b in vim.buffers: - if b is not cb: - vim.command('bwipeout! ' + str(b.number)) - del b - cb.append('w.valid: ' + repr([w.valid for w in ws])) - cb.append('t.valid: ' + repr([t.valid for t in ts])) - del w - del t - del ts - del ws -EOF -:tabonly! -:only! -:" -:" Test types -py << trim EOF - for expr, attr in ( - ('vim.vars', 'Dictionary'), - ('vim.options', 'Options'), - ('vim.bindeval("{}")', 'Dictionary'), - ('vim.bindeval("[]")', 'List'), - ('vim.bindeval("function(\'tr\')")', 'Function'), - ('vim.current.buffer', 'Buffer'), - ('vim.current.range', 'Range'), - ('vim.current.window', 'Window'), - ('vim.current.tabpage', 'TabPage'), - ): - cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr))) - del expr - del attr -EOF -:" -:" Test __dir__() method -py << trim EOF - for name, o in ( - ('current', vim.current), - ('buffer', vim.current.buffer), - ('window', vim.current.window), - ('tabpage', vim.current.tabpage), - ('range', vim.current.range), - ('dictionary', vim.bindeval('{}')), - ('list', vim.bindeval('[]')), - ('function', vim.bindeval('function("tr")')), - ('output', sys.stdout), - ): - cb.append(name + ':' + ','.join(dir(o))) - del name - del o -EOF -:" -:" Test vim.*.__new__ -:$put =string(pyeval('vim.Dictionary({})')) -:$put =string(pyeval('vim.Dictionary(a=1)')) -:$put =string(pyeval('vim.Dictionary(((''a'', 1),))')) -:$put =string(pyeval('vim.List()')) -:$put =string(pyeval('vim.List(iter(''abc7''))')) -:$put =string(pyeval('vim.Function(''tr'')')) -:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4])')) -:$put =string(pyeval('vim.Function(''tr'', args=[])')) -:$put =string(pyeval('vim.Function(''tr'', self={})')) -:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4], self={})')) -:$put ='auto_rebind' -:$put =string(pyeval('vim.Function(''tr'', auto_rebind=False)')) -:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4], auto_rebind=False)')) -:$put =string(pyeval('vim.Function(''tr'', args=[], auto_rebind=False)')) -:$put =string(pyeval('vim.Function(''tr'', self={}, auto_rebind=False)')) -:$put =string(pyeval('vim.Function(''tr'', args=[123, 3, 4], self={}, auto_rebind=False)')) -:" -:" Test vim.Function -:function Args(...) -: return a:000 -:endfunction -:function SelfArgs(...) dict -: return [a:000, self] -:endfunction -:" The following four lines should not crash -:let Pt = function('tr', [[]], {'l': []}) -:py Pt = vim.bindeval('Pt') -:unlet Pt -:py del Pt -py << trim EOF - def ecall(out_prefix, func, *args, **kwargs): - line = out_prefix + ': ' - try: - ret = func(*args, **kwargs) - except Exception: - line += '!exception: ' + emsg(sys.exc_info()) - else: - line += '!result: ' + vim.Function('string')(ret) - cb.append(line) - a = vim.Function('Args') - pa1 = vim.Function('Args', args=['abcArgsPA1']) - pa2 = vim.Function('Args', args=[]) - pa3 = vim.Function('Args', args=['abcArgsPA3'], self={'abcSelfPA3': 'abcSelfPA3Val'}) - pa4 = vim.Function('Args', self={'abcSelfPA4': 'abcSelfPA4Val'}) - cb.append('a: ' + repr(a)) - cb.append('pa1: ' + repr(pa1)) - cb.append('pa2: ' + repr(pa2)) - cb.append('pa3: ' + repr(pa3)) - cb.append('pa4: ' + repr(pa4)) - sa = vim.Function('SelfArgs') - psa1 = vim.Function('SelfArgs', args=['abcArgsPSA1']) - psa2 = vim.Function('SelfArgs', args=[]) - psa3 = vim.Function('SelfArgs', args=['abcArgsPSA3'], self={'abcSelfPSA3': 'abcSelfPSA3Val'}) - psa4 = vim.Function('SelfArgs', self={'abcSelfPSA4': 'abcSelfPSA4Val'}) - psa5 = vim.Function('SelfArgs', self={'abcSelfPSA5': 'abcSelfPSA5Val'}, auto_rebind=0) - psa6 = vim.Function('SelfArgs', args=['abcArgsPSA6'], self={'abcSelfPSA6': 'abcSelfPSA6Val'}, auto_rebind=()) - psa7 = vim.Function('SelfArgs', args=['abcArgsPSA7'], auto_rebind=[]) - psa8 = vim.Function('SelfArgs', auto_rebind=False) - psa9 = vim.Function('SelfArgs', self={'abcSelfPSA9': 'abcSelfPSA9Val'}, auto_rebind=True) - psaA = vim.Function('SelfArgs', args=['abcArgsPSAA'], self={'abcSelfPSAA': 'abcSelfPSAAVal'}, auto_rebind=1) - psaB = vim.Function('SelfArgs', args=['abcArgsPSAB'], auto_rebind={'abcARPSAB': 'abcARPSABVal'}) - psaC = vim.Function('SelfArgs', auto_rebind=['abcARPSAC']) - cb.append('sa: ' + repr(sa)) - cb.append('psa1: ' + repr(psa1)) - cb.append('psa2: ' + repr(psa2)) - cb.append('psa3: ' + repr(psa3)) - cb.append('psa4: ' + repr(psa4)) - cb.append('psa5: ' + repr(psa5)) - cb.append('psa6: ' + repr(psa6)) - cb.append('psa7: ' + repr(psa7)) - cb.append('psa8: ' + repr(psa8)) - cb.append('psa9: ' + repr(psa9)) - cb.append('psaA: ' + repr(psaA)) - cb.append('psaB: ' + repr(psaB)) - cb.append('psaC: ' + repr(psaC)) - - psar = vim.Function('SelfArgs', args=[{'abcArgsPSAr': 'abcArgsPSArVal'}], self={'abcSelfPSAr': 'abcSelfPSArVal'}) - psar.args[0]['abcArgsPSAr2'] = [psar.self, psar.args[0]] - psar.self['rec'] = psar - psar.self['self'] = psar.self - psar.self['args'] = psar.args - - try: - cb.append('psar: ' + repr(psar)) - except Exception: - cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) -EOF -:$put ='s(a): '.string(pyeval('a')) -:$put ='s(pa1): '.string(pyeval('pa1')) -:$put ='s(pa2): '.string(pyeval('pa2')) -:$put ='s(pa3): '.string(pyeval('pa3')) -:$put ='s(pa4): '.string(pyeval('pa4')) -:$put ='s(sa): '.string(pyeval('sa')) -:$put ='s(psa1): '.string(pyeval('psa1')) -:$put ='s(psa2): '.string(pyeval('psa2')) -:$put ='s(psa3): '.string(pyeval('psa3')) -:$put ='s(psa4): '.string(pyeval('psa4')) -:$put ='s(psa5): '.string(pyeval('psa5')) -:$put ='s(psa6): '.string(pyeval('psa6')) -:$put ='s(psa7): '.string(pyeval('psa7')) -:$put ='s(psa8): '.string(pyeval('psa8')) -:$put ='s(psa9): '.string(pyeval('psa9')) -:$put ='s(psaA): '.string(pyeval('psaA')) -:$put ='s(psaB): '.string(pyeval('psaB')) -:$put ='s(psaC): '.string(pyeval('psaC')) -: -:for v in ['sa', 'psa1', 'psa2', 'psa3', 'psa4', 'psa5', 'psa6', 'psa7', 'psa8', 'psa9', 'psaA', 'psaB', 'psaC'] -: let d = {'f': pyeval(v)} -: $put ='d.'.v.'(): '.string(d.f()) -:endfor -: -:py ecall('a()', a, ) -:py ecall('pa1()', pa1, ) -:py ecall('pa2()', pa2, ) -:py ecall('pa3()', pa3, ) -:py ecall('pa4()', pa4, ) -:py ecall('sa()', sa, ) -:py ecall('psa1()', psa1, ) -:py ecall('psa2()', psa2, ) -:py ecall('psa3()', psa3, ) -:py ecall('psa4()', psa4, ) -: -:py ecall('a(42, 43)', a, 42, 43) -:py ecall('pa1(42, 43)', pa1, 42, 43) -:py ecall('pa2(42, 43)', pa2, 42, 43) -:py ecall('pa3(42, 43)', pa3, 42, 43) -:py ecall('pa4(42, 43)', pa4, 42, 43) -:py ecall('sa(42, 43)', sa, 42, 43) -:py ecall('psa1(42, 43)', psa1, 42, 43) -:py ecall('psa2(42, 43)', psa2, 42, 43) -:py ecall('psa3(42, 43)', psa3, 42, 43) -:py ecall('psa4(42, 43)', psa4, 42, 43) -: -:py ecall('a(42, self={"20": 1})', a, 42, self={'20': 1}) -:py ecall('pa1(42, self={"20": 1})', pa1, 42, self={'20': 1}) -:py ecall('pa2(42, self={"20": 1})', pa2, 42, self={'20': 1}) -:py ecall('pa3(42, self={"20": 1})', pa3, 42, self={'20': 1}) -:py ecall('pa4(42, self={"20": 1})', pa4, 42, self={'20': 1}) -:py ecall('sa(42, self={"20": 1})', sa, 42, self={'20': 1}) -:py ecall('psa1(42, self={"20": 1})', psa1, 42, self={'20': 1}) -:py ecall('psa2(42, self={"20": 1})', psa2, 42, self={'20': 1}) -:py ecall('psa3(42, self={"20": 1})', psa3, 42, self={'20': 1}) -:py ecall('psa4(42, self={"20": 1})', psa4, 42, self={'20': 1}) -: -:py ecall('a(self={"20": 1})', a, self={'20': 1}) -:py ecall('pa1(self={"20": 1})', pa1, self={'20': 1}) -:py ecall('pa2(self={"20": 1})', pa2, self={'20': 1}) -:py ecall('pa3(self={"20": 1})', pa3, self={'20': 1}) -:py ecall('pa4(self={"20": 1})', pa4, self={'20': 1}) -:py ecall('sa(self={"20": 1})', sa, self={'20': 1}) -:py ecall('psa1(self={"20": 1})', psa1, self={'20': 1}) -:py ecall('psa2(self={"20": 1})', psa2, self={'20': 1}) -:py ecall('psa3(self={"20": 1})', psa3, self={'20': 1}) -:py ecall('psa4(self={"20": 1})', psa4, self={'20': 1}) -py << trim EOF - def s(v): - if v is None: - return repr(v) - else: - return vim.Function('string')(v) - - cb.append('a.args: ' + s(a.args)) - cb.append('pa1.args: ' + s(pa1.args)) - cb.append('pa2.args: ' + s(pa2.args)) - cb.append('pa3.args: ' + s(pa3.args)) - cb.append('pa4.args: ' + s(pa4.args)) - cb.append('sa.args: ' + s(sa.args)) - cb.append('psa1.args: ' + s(psa1.args)) - cb.append('psa2.args: ' + s(psa2.args)) - cb.append('psa3.args: ' + s(psa3.args)) - cb.append('psa4.args: ' + s(psa4.args)) - - cb.append('a.self: ' + s(a.self)) - cb.append('pa1.self: ' + s(pa1.self)) - cb.append('pa2.self: ' + s(pa2.self)) - cb.append('pa3.self: ' + s(pa3.self)) - cb.append('pa4.self: ' + s(pa4.self)) - cb.append('sa.self: ' + s(sa.self)) - cb.append('psa1.self: ' + s(psa1.self)) - cb.append('psa2.self: ' + s(psa2.self)) - cb.append('psa3.self: ' + s(psa3.self)) - cb.append('psa4.self: ' + s(psa4.self)) - - cb.append('a.name: ' + s(a.name)) - cb.append('pa1.name: ' + s(pa1.name)) - cb.append('pa2.name: ' + s(pa2.name)) - cb.append('pa3.name: ' + s(pa3.name)) - cb.append('pa4.name: ' + s(pa4.name)) - cb.append('sa.name: ' + s(sa.name)) - cb.append('psa1.name: ' + s(psa1.name)) - cb.append('psa2.name: ' + s(psa2.name)) - cb.append('psa3.name: ' + s(psa3.name)) - cb.append('psa4.name: ' + s(psa4.name)) - - cb.append('a.auto_rebind: ' + s(a.auto_rebind)) - cb.append('pa1.auto_rebind: ' + s(pa1.auto_rebind)) - cb.append('pa2.auto_rebind: ' + s(pa2.auto_rebind)) - cb.append('pa3.auto_rebind: ' + s(pa3.auto_rebind)) - cb.append('pa4.auto_rebind: ' + s(pa4.auto_rebind)) - cb.append('sa.auto_rebind: ' + s(sa.auto_rebind)) - cb.append('psa1.auto_rebind: ' + s(psa1.auto_rebind)) - cb.append('psa2.auto_rebind: ' + s(psa2.auto_rebind)) - cb.append('psa3.auto_rebind: ' + s(psa3.auto_rebind)) - cb.append('psa4.auto_rebind: ' + s(psa4.auto_rebind)) - cb.append('psa5.auto_rebind: ' + s(psa5.auto_rebind)) - cb.append('psa6.auto_rebind: ' + s(psa6.auto_rebind)) - cb.append('psa7.auto_rebind: ' + s(psa7.auto_rebind)) - cb.append('psa8.auto_rebind: ' + s(psa8.auto_rebind)) - cb.append('psa9.auto_rebind: ' + s(psa9.auto_rebind)) - cb.append('psaA.auto_rebind: ' + s(psaA.auto_rebind)) - cb.append('psaB.auto_rebind: ' + s(psaB.auto_rebind)) - cb.append('psaC.auto_rebind: ' + s(psaC.auto_rebind)) - - del s - - del a - del pa1 - del pa2 - del pa3 - del pa4 - del sa - del psa1 - del psa2 - del psa3 - del psa4 - del psa5 - del psa6 - del psa7 - del psa8 - del psa9 - del psaA - del psaB - del psaC - del psar - - del ecall -EOF -:" -:" Test stdout/stderr -:redir => messages -:py sys.stdout.write('abc8') ; sys.stdout.write('def') -:py sys.stderr.write('abc9') ; sys.stderr.write('def') -:py sys.stdout.writelines(iter('abcA')) -:py sys.stderr.writelines(iter('abcB')) -:redir END -:$put =string(substitute(messages, '\d\+', '', 'g')) -:" Test subclassing -:fun Put(...) -: $put =string(a:000) -: return a:000 -:endfun -py << trim EOF - class DupDict(vim.Dictionary): - def __setitem__(self, key, value): - super(DupDict, self).__setitem__(key, value) - super(DupDict, self).__setitem__('dup_' + key, value) - dd = DupDict() - dd['a'] = 'b' - - class DupList(vim.List): - def __getitem__(self, idx): - return [super(DupList, self).__getitem__(idx)] * 2 - - dl = DupList() - dl2 = DupList(iter('abcC')) - dl.extend(dl2[0]) - - class DupFun(vim.Function): - def __call__(self, arg): - return super(DupFun, self).__call__(arg, arg) - - df = DupFun('Put') -EOF -:$put =string(sort(keys(pyeval('dd')))) -:$put =string(pyeval('dl')) -:$put =string(pyeval('dl2')) -:$put =string(pyeval('df(2)')) -:$put =string(pyeval('dl') is# pyeval('dl')) -:$put =string(pyeval('dd') is# pyeval('dd')) -:$put =string(pyeval('df')) -:delfunction Put -py << trim - del DupDict - del DupList - del DupFun - del dd - del dl - del dl2 - del df -. -:" -:" Test chdir -py << trim EOF - import os - fnamemodify = vim.Function('fnamemodify') - cb.append(fnamemodify('.', ':p:h:t')) - cb.append(vim.eval('@%')) - os.chdir('..') - path = fnamemodify('.', ':p:h:t') - if path != 'src': - # Running tests from a shadow directory, so move up another level - # This will result in @% looking like shadow/testdir/test86.in, hence the - # extra fnamemodify - os.chdir('..') - cb.append(fnamemodify('.', ':p:h:t')) - cb.append(fnamemodify(vim.eval('@%'), ':s?^%s.??' % path).replace(os.path.sep, '/')) - os.chdir(path) - del path - else: - cb.append(fnamemodify('.', ':p:h:t')) - cb.append(vim.eval('@%').replace(os.path.sep, '/')) - os.chdir('testdir') - cb.append(fnamemodify('.', ':p:h:t')) - cb.append(vim.eval('@%')) - del fnamemodify -EOF -:" -:" Test errors -:fun F() dict -:endfun -:fun D() -:endfun -py << trim EOF - d = vim.Dictionary() - ned = vim.Dictionary(foo='bar', baz='abcD') - dl = vim.Dictionary(a=1) - dl.locked = True - l = vim.List() - ll = vim.List('abcE') - ll.locked = True - nel = vim.List('abcO') - f = vim.Function('string') - fd = vim.Function('F') - fdel = vim.Function('D') - vim.command('delfunction D') - - def subexpr_test(expr, name, subexprs): - cb.append('>>> Testing %s using %s' % (name, expr)) - for subexpr in subexprs: - ee(expr % subexpr) - cb.append('<<< Finished') - - def stringtochars_test(expr): - return subexpr_test(expr, 'StringToChars', ( - '1', # Fail type checks - 'u"\\0"', # Fail PyString_AsStringAndSize(bytes, , NULL) check - '"\\0"', # Fail PyString_AsStringAndSize(object, , NULL) check - )) - - class Mapping(object): - def __init__(self, d): - self.d = d - - def __getitem__(self, key): - return self.d[key] - - def keys(self): - return self.d.keys() - - def items(self): - return self.d.items() - - def convertfrompyobject_test(expr, recurse=True): - # pydict_to_tv - stringtochars_test(expr % '{%s : 1}') - if recurse: - convertfrompyobject_test(expr % '{"abcF" : %s}', False) - # pymap_to_tv - stringtochars_test(expr % 'Mapping({%s : 1})') - if recurse: - convertfrompyobject_test(expr % 'Mapping({"abcG" : %s})', False) - # pyseq_to_tv - iter_test(expr) - return subexpr_test(expr, 'ConvertFromPyObject', ( - 'None', # Not conversible - '{"": 1}', # Empty key not allowed - '{u"": 1}', # Same, but with unicode object - 'FailingMapping()', # - 'FailingMappingKey()', # - 'FailingNumber()', # - )) - - def convertfrompymapping_test(expr): - convertfrompyobject_test(expr) - return subexpr_test(expr, 'ConvertFromPyMapping', ( - '[]', - )) - - def iter_test(expr): - return subexpr_test(expr, '*Iter*', ( - 'FailingIter()', - 'FailingIterNext()', - )) - - def number_test(expr, natural=False, unsigned=False): - if natural: - unsigned = True - return subexpr_test(expr, 'NumberToLong', ( - '[]', - 'None', - ) + (unsigned and ('-1',) or ()) - + (natural and ('0',) or ())) - - class FailingTrue(object): - def __nonzero__(self): - raise NotImplementedError('bool') - - class FailingIter(object): - def __iter__(self): - raise NotImplementedError('iter') - - class FailingIterNext(object): - def __iter__(self): - return self - - def next(self): - raise NotImplementedError('next') - - class FailingIterNextN(object): - def __init__(self, n): - self.n = n - - def __iter__(self): - return self - - def next(self): - if self.n: - self.n -= 1 - return 1 - else: - raise NotImplementedError('next N') - - class FailingMappingKey(object): - def __getitem__(self, item): - raise NotImplementedError('getitem:mappingkey') - - def keys(self): - return list("abcH") - - class FailingMapping(object): - def __getitem__(self): - raise NotImplementedError('getitem:mapping') - - def keys(self): - raise NotImplementedError('keys') - - class FailingList(list): - def __getitem__(self, idx): - if i == 2: - raise NotImplementedError('getitem:list') - else: - return super(FailingList, self).__getitem__(idx) - - class NoArgsCall(object): - def __call__(self): - pass - - class FailingCall(object): - def __call__(self, path): - raise NotImplementedError('call') - - class FailingNumber(object): - def __int__(self): - raise NotImplementedError('int') - - cb.append("> Output") - cb.append(">> OutputSetattr") - ee('del sys.stdout.softspace') - number_test('sys.stdout.softspace = %s', unsigned=True) - number_test('sys.stderr.softspace = %s', unsigned=True) - ee('assert sys.stdout.isatty()==False') - ee('assert sys.stdout.seekable()==False') - ee('sys.stdout.close()') - ee('sys.stdout.flush()') - ee('assert sys.stderr.isatty()==False') - ee('assert sys.stderr.seekable()==False') - ee('sys.stderr.close()') - ee('sys.stderr.flush()') - ee('sys.stdout.attr = None') - cb.append(">> OutputWrite") - ee('assert sys.stdout.writable()==True') - ee('assert sys.stdout.readable()==False') - ee('assert sys.stderr.writable()==True') - ee('assert sys.stderr.readable()==False') - ee('assert sys.stdout.closed()==False') - ee('assert sys.stderr.closed()==False') - ee('assert sys.stdout.errors=="strict"') - ee('assert sys.stderr.errors=="strict"') - ee('assert sys.stdout.encoding==sys.stderr.encoding') - ee('sys.stdout.write(None)') - cb.append(">> OutputWriteLines") - ee('sys.stdout.writelines(None)') - ee('sys.stdout.writelines([1])') - iter_test('sys.stdout.writelines(%s)') - cb.append("> VimCommand") - stringtochars_test('vim.command(%s)') - ee('vim.command("", 2)') - #! Not checked: vim->python exceptions translating: checked later - cb.append("> VimToPython") - #! Not checked: everything: needs errors in internal python functions - cb.append("> VimEval") - stringtochars_test('vim.eval(%s)') - ee('vim.eval("", FailingTrue())') - #! Not checked: everything: needs errors in internal python functions - cb.append("> VimEvalPy") - stringtochars_test('vim.bindeval(%s)') - ee('vim.eval("", 2)') - #! Not checked: vim->python exceptions translating: checked later - cb.append("> VimStrwidth") - stringtochars_test('vim.strwidth(%s)') - cb.append("> VimForeachRTP") - ee('vim.foreach_rtp(None)') - ee('vim.foreach_rtp(NoArgsCall())') - ee('vim.foreach_rtp(FailingCall())') - ee('vim.foreach_rtp(int, 2)') - cb.append('> import') - old_rtp = vim.options['rtp'] - vim.options['rtp'] = os.getcwd().replace('\\', '\\\\').replace(',', '\\,') - ee('import xxx_no_such_module_xxx') - ee('import failing_import') - ee('import failing') - vim.options['rtp'] = old_rtp - del old_rtp - cb.append("> Options") - cb.append(">> OptionsItem") - ee('vim.options["abcQ"]') - ee('vim.options[""]') - stringtochars_test('vim.options[%s]') - cb.append(">> OptionsContains") - stringtochars_test('%s in vim.options') - cb.append("> Dictionary") - cb.append(">> DictionaryConstructor") - ee('vim.Dictionary("abcI")') - ##! Not checked: py_dict_alloc failure - cb.append(">> DictionarySetattr") - ee('del d.locked') - ee('d.locked = FailingTrue()') - ee('vim.vvars.locked = False') - ee('d.scope = True') - ee('d.xxx = True') - cb.append(">> _DictionaryItem") - ee('d.get("a", 2, 3)') - stringtochars_test('d.get(%s)') - ee('d.pop("a")') - ee('dl.pop("a")') - cb.append(">> DictionaryContains") - ee('"" in d') - ee('0 in d') - cb.append(">> DictionaryIterNext") - ee('for i in ned: ned["a"] = 1') - del i - cb.append(">> DictionaryAssItem") - ee('dl["b"] = 1') - stringtochars_test('d[%s] = 1') - convertfrompyobject_test('d["a"] = %s') - cb.append(">> DictionaryUpdate") - cb.append(">>> kwargs") - cb.append(">>> iter") - ee('d.update(FailingMapping())') - ee('d.update([FailingIterNext()])') - ee('d.update([FailingIterNextN(1)])') - iter_test('d.update(%s)') - convertfrompyobject_test('d.update(%s)') - stringtochars_test('d.update(((%s, 0),))') - convertfrompyobject_test('d.update((("a", %s),))') - cb.append(">> DictionaryPopItem") - ee('d.popitem(1, 2)') - cb.append(">> DictionaryHasKey") - ee('d.has_key()') - cb.append("> List") - cb.append(">> ListConstructor") - ee('vim.List(1, 2)') - ee('vim.List(a=1)') - iter_test('vim.List(%s)') - convertfrompyobject_test('vim.List([%s])') - cb.append(">> ListItem") - ee('l[1000]') - cb.append(">> ListAssItem") - ee('ll[1] = 2') - ee('l[1000] = 3') - cb.append(">> ListAssSlice") - ee('ll[1:100] = "abcJ"') - iter_test('l[:] = %s') - ee('nel[1:10:2] = "abcK"') - cb.append(repr(tuple(nel))) - ee('nel[1:10:2] = "a"') - cb.append(repr(tuple(nel))) - ee('nel[1:1:-1] = "a"') - cb.append(repr(tuple(nel))) - ee('nel[:] = FailingIterNextN(2)') - cb.append(repr(tuple(nel))) - convertfrompyobject_test('l[:] = [%s]') - cb.append(">> ListConcatInPlace") - iter_test('l.extend(%s)') - convertfrompyobject_test('l.extend([%s])') - cb.append(">> ListSetattr") - ee('del l.locked') - ee('l.locked = FailingTrue()') - ee('l.xxx = True') - cb.append("> Function") - cb.append(">> FunctionConstructor") - cb.append(">>> FunctionConstructor") - ee('vim.Function("123")') - ee('vim.Function("xxx_non_existent_function_xxx")') - ee('vim.Function("xxx#non#existent#function#xxx")') - ee('vim.Function("xxx_non_existent_function_xxx2", args=[])') - ee('vim.Function("xxx_non_existent_function_xxx3", self={})') - ee('vim.Function("xxx_non_existent_function_xxx4", args=[], self={})') - cb.append(">>> FunctionNew") - ee('vim.Function("tr", self="abcFuncSelf")') - ee('vim.Function("tr", args=427423)') - ee('vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2")') - ee('vim.Function(self="abcFuncSelf2", args="abcFuncArgs2")') - ee('vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2")') - ee('vim.Function("tr", "")') - cb.append(">> FunctionCall") - convertfrompyobject_test('f(%s)') - convertfrompymapping_test('fd(self=%s)') - cb.append("> TabPage") - cb.append(">> TabPageAttr") - ee('vim.current.tabpage.xxx') - cb.append("> TabList") - cb.append(">> TabListItem") - ee('vim.tabpages[1000]') - cb.append("> Window") - cb.append(">> WindowAttr") - ee('vim.current.window.xxx') - cb.append(">> WindowSetattr") - ee('vim.current.window.buffer = 0') - ee('vim.current.window.cursor = (100000000, 100000000)') - ee('vim.current.window.cursor = True') - number_test('vim.current.window.height = %s', unsigned=True) - number_test('vim.current.window.width = %s', unsigned=True) - ee('vim.current.window.xxxxxx = True') - cb.append("> WinList") - cb.append(">> WinListItem") - ee('vim.windows[1000]') - cb.append("> Buffer") - cb.append(">> StringToLine (indirect)") - ee('vim.current.buffer[0] = u"\\na"') - ee('vim.current.buffer[0] = "\\na"') - cb.append(">> SetBufferLine (indirect)") - ee('vim.current.buffer[0] = True') - cb.append(">> SetBufferLineList (indirect)") - ee('vim.current.buffer[:] = True') - ee('vim.current.buffer[:] = ["\\na", "bc"]') - cb.append(">> InsertBufferLines (indirect)") - ee('vim.current.buffer.append(None)') - ee('vim.current.buffer.append(["\\na", "bc"])') - ee('vim.current.buffer.append("\\nbc")') - cb.append(">> RBItem") - ee('vim.current.buffer[100000000]') - cb.append(">> RBAsItem") - ee('vim.current.buffer[100000000] = ""') - cb.append(">> BufferAttr") - ee('vim.current.buffer.xxx') - cb.append(">> BufferSetattr") - ee('vim.current.buffer.name = True') - ee('vim.current.buffer.xxx = True') - cb.append(">> BufferMark") - ee('vim.current.buffer.mark(0)') - ee('vim.current.buffer.mark("abcM")') - ee('vim.current.buffer.mark("!")') - cb.append(">> BufferRange") - ee('vim.current.buffer.range(1, 2, 3)') - cb.append("> BufMap") - cb.append(">> BufMapItem") - ee('vim.buffers[100000000]') - number_test('vim.buffers[%s]', natural=True) - cb.append("> Current") - cb.append(">> CurrentGetattr") - ee('vim.current.xxx') - cb.append(">> CurrentSetattr") - ee('vim.current.line = True') - ee('vim.current.buffer = True') - ee('vim.current.window = True') - ee('vim.current.tabpage = True') - ee('vim.current.xxx = True') - del d - del ned - del dl - del l - del ll - del nel - del f - del fd - del fdel - del subexpr_test - del stringtochars_test - del Mapping - del convertfrompyobject_test - del convertfrompymapping_test - del iter_test - del number_test - del FailingTrue - del FailingIter - del FailingIterNext - del FailingIterNextN - del FailingMapping - del FailingMappingKey - del FailingList - del NoArgsCall - del FailingCall - del FailingNumber -EOF -:delfunction F -:" -:" Test import -py << trim EOF - sys.path.insert(0, os.path.join(os.getcwd(), 'python_before')) - sys.path.append(os.path.join(os.getcwd(), 'python_after')) - vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\') - l = [] - def callback(path): - l.append(path[-len('/testdir'):].replace(os.path.sep, '/')) - vim.foreach_rtp(callback) - cb.append(repr(l)) - del l - def callback(path): - return path[-len('/testdir'):].replace(os.path.sep, '/') - cb.append(repr(vim.foreach_rtp(callback))) - del callback - from module import dir as d - from modulex import ddir - cb.append(d + ',' + ddir) - import before - cb.append(before.dir) - import after - cb.append(after.dir) - import topmodule as tm - import topmodule.submodule as tms - import topmodule.submodule.subsubmodule.subsubsubmodule as tmsss - cb.append(tm.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/__init__.py'):]) - cb.append(tms.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/__init__.py'):]) - cb.append(tmsss.__file__.replace('.pyc', '.py').replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/subsubmodule/subsubsubmodule.py'):]) - del before - del after - del d - del ddir - del tm - del tms - del tmsss -EOF -:" -:" Test exceptions -:fun Exe(e) -: execute a:e -:endfun -py << trim EOF - Exe = vim.bindeval('function("Exe")') - ee('vim.command("throw \'abcN\'")') - ee('Exe("throw \'def\'")') - ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")') - ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")') - ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")') - ee('vim.eval("xxx_unknown_function_xxx()")') - ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")') - del Exe -EOF -:delfunction Exe -:" -:" Regression: interrupting vim.command propagates to next vim.command -py << trim EOF - def test_keyboard_interrupt(): - try: - vim.command('while 1 | endwhile') - except KeyboardInterrupt: - cb.append('Caught KeyboardInterrupt') - except Exception: - cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) - else: - cb.append('!!!!!!!! No exception') - try: - vim.command('$ put =\'Running :put\'') - except KeyboardInterrupt: - cb.append('!!!!!!!! Caught KeyboardInterrupt') - except Exception: - cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) - else: - cb.append('No exception') -EOF -:debuggreedy -:call inputsave() -:call feedkeys("s\ns\ns\ns\nq\n") -:redir => output -:debug silent! py test_keyboard_interrupt() -:redir END -:0 debuggreedy -:call inputrestore() -:silent $put =output -:unlet output -:py del test_keyboard_interrupt -:" -:" Cleanup -py << trim EOF - del cb - del ee - del emsg - del sys - del os - del vim -EOF -:endfun -:" -:fun RunTest() -:let checkrefs = !empty($PYTHONDUMPREFS) -:let start = getline(1, '$') -:for i in range(checkrefs ? 10 : 1) -: if i != 0 -: %d _ -: call setline(1, start) -: endif -: call Test() -: if i == 0 -: let result = getline(1, '$') -: endif -:endfor -:if checkrefs -: %d _ -: call setline(1, result) -:endif -:endfun -:" -:call RunTest() -:delfunction RunTest -:delfunction Test -:call garbagecollect(1) -:" -:/^start:/,$wq! test.out -:" vim: et ts=4 isk-=\: -:while getchar(0) isnot 0|endwhile -ENDTEST - -start: diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok deleted file mode 100644 index 4f6d4b3060..0000000000 --- a/src/testdir/test86.ok +++ /dev/null @@ -1,1445 +0,0 @@ -start: -[1, 'as''d', [1, 2, function('strlen'), {'a': 1}]] -[1, 2, function('strlen'), {'a': 1}] -Vim(put):E684: -[0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] -[0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] -1 -['-1', '0', '1', 'b', 'f'] -['asd', -1L, , , ] -[('-1', ), ('0', -1L), ('1', 'asd'), ('b', ), ('f', )] -'-1' : {'a': 1} -'0' : -1 -'1' : 'asd' -'b' : [1, 2, function('strlen')] -'f' : function('1') -[0, function('strlen')] -[3] -[1, 2, function('strlen')] -[1, 2, function('strlen')] -1 -'asd' -2 -True -False -True -False -['0'] -{'0': -1} -('0', -1L) -None -[] -[0, 1, 2, 3] -[0, 1, 2, 3] -[0, 1, 3] -[0, 1] -[0, 1] -[0, 1] -[0, 1, 2, 3] -[0, 1, 2, 3] -[0, 2, 3] -[2, 3] -[2, 3] -[2, 3] -[1, 3] -[0, 2] -[0, 1, 2, 3] -['a', 0, 1, 2, 3] -[0, 'b', 2, 3] -[0, 1, 'c'] -[0, 1, 2, 3, 'd'] -[0, 1, 2, 'e', 3] -['f', 2, 3] -[0, 1, 'g', 2, 3] -['h'] -[0, 1, 10, 3, 20, 5, 6, 7] -[0, 1, 2, 3, 20, 5, 10, 7] -[0, 1, 2, 3, 4, 5, 6, 7] -[0, 1, 2, 3, 4, 5, 6, 7] -[0, 1, 2, 3, 4, 5, 6, 7] -l[2] threw vim.error: error:('list is locked',) -[0, 1, 2, 3] -[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd'] -[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}] -[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New'] -l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: DictNew',) -f(1, 2, 3):error:('Vim:E117: Unknown function: New',) -[0.0, 0.0] -KeyError -TypeError -TypeError -ValueError -TypeError -TypeError -KeyError -KeyError -d : locked:0;scope:0 -dl : locked:1;scope:0 -v: : locked:2;scope:1 -g: : locked:0;scope:2 -d:{'abc2': 1} -dl:{'def': 1} -l : locked:0 -ll : locked:1 -l:[0] -ll:[1] -[0, 1, 2] -['a', 'b'] -['c', 1] -['d', ['e']] -pyeval("None") = v:none -0.0 -"\0": Vim(let):E859: -{"\0": 1}: Vim(let):E859: -undefined_name: Vim(let):NameE -vim: Vim(let):E859: -[1] -[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1] -[0, 1, 2, 3] -[2, 3, 4, 5] -[0, 1] -[4, 5] -[2, 3] -[] -[2, 3] -[] -[0, 1, 2, 3, 4, 5] -[0, 1, 2, 3, 4, 5] -[0, 1, 2, 3, 4, 5] -[4, 3] -[0, 2, 4] -[] -Abc -bac -def -bar -jkl -wopts iters equal: 1 -bopts iters equal: 1 ->>> paste - g/w/b:1/0/0 - g/w/b (in):1/0/0 - p/gopts1: False - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1! KeyError - inv: 2! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 1 - W: 1:1 2:1 3:1 4:1 - B: 1:1 2:1 3:1 4:1 - del wopts3! KeyError - del bopts3! KeyError - G: 1 - W: 1:1 2:1 3:1 4:1 - B: 1:1 2:1 3:1 4:1 ->>> previewheight - g/w/b:1/0/0 - g/w/b (in):1/0/0 - p/gopts1: 12 - inv: 'a'! TypeError - p/wopts1! KeyError - inv: 'a'! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1! KeyError - inv: 'a'! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 5 - W: 1:5 2:5 3:5 4:5 - B: 1:5 2:5 3:5 4:5 - del wopts3! KeyError - del bopts3! KeyError - G: 5 - W: 1:5 2:5 3:5 4:5 - B: 1:5 2:5 3:5 4:5 ->>> operatorfunc - g/w/b:1/0/0 - g/w/b (in):1/0/0 - p/gopts1: '' - inv: 2! TypeError - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1! KeyError - inv: 2! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 'A' - W: 1:'A' 2:'A' 3:'A' 4:'A' - B: 1:'A' 2:'A' 3:'A' 4:'A' - del wopts3! KeyError - del bopts3! KeyError - G: 'A' - W: 1:'A' 2:'A' 3:'A' 4:'A' - B: 1:'A' 2:'A' 3:'A' 4:'A' ->>> number - g/w/b:0/1/0 - g/w/b (in):0/1/0 - p/gopts1! KeyError - inv: 0! KeyError - gopts1! KeyError - p/wopts1: False - p/bopts1! KeyError - inv: 0! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 0 - W: 1:1 2:1 3:0 4:0 - B: 1:1 2:1 3:0 4:0 - del wopts3! ValueError - del bopts3! KeyError - G: 0 - W: 1:1 2:1 3:0 4:0 - B: 1:1 2:1 3:0 4:0 ->>> numberwidth - g/w/b:0/1/0 - g/w/b (in):0/1/0 - p/gopts1! KeyError - inv: -100! KeyError - gopts1! KeyError - p/wopts1: 8 - inv: -100! error - p/bopts1! KeyError - inv: -100! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 8 - W: 1:3 2:5 3:2 4:8 - B: 1:3 2:5 3:2 4:8 - del wopts3! ValueError - del bopts3! KeyError - G: 8 - W: 1:3 2:5 3:2 4:8 - B: 1:3 2:5 3:2 4:8 ->>> colorcolumn - g/w/b:0/1/0 - g/w/b (in):0/1/0 - p/gopts1! KeyError - inv: 'abc4'! KeyError - gopts1! KeyError - p/wopts1: '' - inv: 'abc4'! error - p/bopts1! KeyError - inv: 'abc4'! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: '' - W: 1:'+2' 2:'+3' 3:'+1' 4:'' - B: 1:'+2' 2:'+3' 3:'+1' 4:'' - del wopts3! ValueError - del bopts3! KeyError - G: '' - W: 1:'+2' 2:'+3' 3:'+1' 4:'' - B: 1:'+2' 2:'+3' 3:'+1' 4:'' ->>> statusline - g/w/b:1/1/0 - g/w/b (in):1/1/0 - p/gopts1: '' - inv: 0! TypeError - p/wopts1: None - inv: 0! TypeError - p/bopts1! KeyError - inv: 0! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: '1' - W: 1:'2' 2:'4' 3:'1' 4:'1' - B: 1:'2' 2:'4' 3:'1' 4:'1' - del bopts3! KeyError - G: '1' - W: 1:'2' 2:'1' 3:'1' 4:'1' - B: 1:'2' 2:'1' 3:'1' 4:'1' ->>> autoindent - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 2! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: False - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 - del wopts3! KeyError - del bopts3! ValueError - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 ->>> shiftwidth - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 3! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 3! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: 8 - G: 8 - W: 1:0 2:2 3:8 4:1 - B: 1:0 2:2 3:8 4:1 - del wopts3! KeyError - del bopts3! ValueError - G: 8 - W: 1:0 2:2 3:8 4:1 - B: 1:0 2:2 3:8 4:1 ->>> omnifunc - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 1! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 1! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: '' - inv: 1! TypeError - G: '' - W: 1:'A' 2:'B' 3:'' 4:'C' - B: 1:'A' 2:'B' 3:'' 4:'C' - del wopts3! KeyError - del bopts3! ValueError - G: '' - W: 1:'A' 2:'B' 3:'' 4:'C' - B: 1:'A' 2:'B' 3:'' 4:'C' ->>> preserveindent - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 2! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: False - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 - del wopts3! KeyError - del bopts3! ValueError - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 ->>> path - g/w/b:1/0/1 - g/w/b (in):1/0/1 - p/gopts1: '.,..,,' - inv: 0! TypeError - p/wopts1! KeyError - inv: 0! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: None - inv: 0! TypeError - G: '.,,' - W: 1:'.,,' 2:',,' 3:'.,,' 4:'.' - B: 1:'.,,' 2:',,' 3:'.,,' 4:'.' - del wopts3! KeyError - G: '.,,' - W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' - B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' -First line -First line -def -First line -Second line -Third line -(7, 2) - -baz -bar -Second line -Third line -foo -1:BufFilePre:1 -1:BufFilePost:1 -testdir/foo -5:BufFilePre:5 -5:BufFilePost:5 -testdir/bar -1:BufFilePre:1 -1:BufFilePost:1 -testdir/test86.in -valid: b:False, cb:True -i: -i2: -i: -i3: -1:= -8:= -9:= -10:= -4 -i4: -i4: -StopIteration -Number of tabs: 4 -Current tab pages: - (1): 1 windows, current is - Windows: - (1): displays buffer ; cursor is at (37, 0) - (2): 1 windows, current is - Windows: - (1): displays buffer ; cursor is at (1, 0) - (3): 2 windows, current is - Windows: - (1): displays buffer ; cursor is at (1, 0) - (2): displays buffer ; cursor is at (1, 0) - (4): 4 windows, current is - Windows: - (1): displays buffer ; cursor is at (1, 0) - (2): displays buffer ; cursor is at (1, 0) - (3): displays buffer ; cursor is at (1, 0) - (4): displays buffer ; cursor is at (1, 0) -Number of windows in current tab page: 4 -Current tab page: -Current window: : is -Current buffer: : is is -ValueError at assigning foreign tab window -Type error at assigning None to vim.current.window -Type error at assigning None to vim.current.tabpage -Type error at assigning None to vim.current.buffer -Current tab page: -Current window: -Current buffer: -Current line: 'Type error at assigning None to vim.current.buffer' -w.valid: [True, False] -t.valid: [True, False, True, False] -vim.vars:Dictionary:True -vim.options:Options:True -vim.bindeval("{}"):Dictionary:True -vim.bindeval("[]"):List:True -vim.bindeval("function('tr')"):Function:True -vim.current.buffer:Buffer:True -vim.current.range:Range:True -vim.current.window:Window:True -vim.current.tabpage:TabPage:True -current:__dir__,__members__,buffer,line,range,tabpage,window -buffer:__dir__,__members__,append,mark,name,number,options,range,valid,vars -window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars,width -tabpage:__dir__,__members__,number,valid,vars,window,windows -range:__dir__,__members__,append,end,start -dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values -list:__dir__,__members__,extend,locked -function:__dir__,__members__,args,auto_rebind,self,softspace -output:__dir__,__members__,close,closed,flush,isatty,readable,seekable,softspace,writable,write,writelines -{} -{'a': 1} -{'a': 1} -[] -['a', 'b', 'c', '7'] -function('tr') -function('tr', [123, 3, 4]) -function('tr') -function('tr', {}) -function('tr', [123, 3, 4], {}) -auto_rebind -function('tr') -function('tr', [123, 3, 4]) -function('tr') -function('tr', {}) -function('tr', [123, 3, 4], {}) -a: -pa1: -pa2: -pa3: -pa4: -sa: -psa1: -psa2: -psa3: -psa4: -psa5: -psa6: -psa7: -psa8: -psa9: -psaA: -psaB: -psaC: -psar: -s(a): function('Args') -s(pa1): function('Args', ['abcArgsPA1']) -s(pa2): function('Args') -s(pa3): function('Args', ['abcArgsPA3'], {'abcSelfPA3': 'abcSelfPA3Val'}) -s(pa4): function('Args', {'abcSelfPA4': 'abcSelfPA4Val'}) -s(sa): function('SelfArgs') -s(psa1): function('SelfArgs', ['abcArgsPSA1']) -s(psa2): function('SelfArgs') -s(psa3): function('SelfArgs', ['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}) -s(psa4): function('SelfArgs', {'abcSelfPSA4': 'abcSelfPSA4Val'}) -s(psa5): function('SelfArgs', {'abcSelfPSA5': 'abcSelfPSA5Val'}) -s(psa6): function('SelfArgs', ['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'}) -s(psa7): function('SelfArgs', ['abcArgsPSA7']) -s(psa8): function('SelfArgs') -s(psa9): function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'}) -s(psaA): function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'}) -s(psaB): function('SelfArgs', ['abcArgsPSAB']) -s(psaC): function('SelfArgs') -d.sa(): [[], {'f': function('SelfArgs')}] -d.psa1(): [['abcArgsPSA1'], {'f': function('SelfArgs', ['abcArgsPSA1'])}] -d.psa2(): [[], {'f': function('SelfArgs')}] -d.psa3(): [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}] -d.psa4(): [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}] -d.psa5(): [[], {'abcSelfPSA5': 'abcSelfPSA5Val'}] -d.psa6(): [['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'}] -d.psa7(): [['abcArgsPSA7'], {'f': function('SelfArgs', ['abcArgsPSA7'])}] -d.psa8(): [[], {'f': function('SelfArgs')}] -d.psa9(): [[], {'f': function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'})}] -d.psaA(): [['abcArgsPSAA'], {'f': function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'})}] -d.psaB(): [['abcArgsPSAB'], {'f': function('SelfArgs', ['abcArgsPSAB'])}] -d.psaC(): [[], {'f': function('SelfArgs')}] -a(): !result: [] -pa1(): !result: ['abcArgsPA1'] -pa2(): !result: [] -pa3(): !result: ['abcArgsPA3'] -pa4(): !result: [] -sa(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa1(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa2(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa3(): !result: [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}] -psa4(): !result: [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}] -a(42, 43): !result: [42, 43] -pa1(42, 43): !result: ['abcArgsPA1', 42, 43] -pa2(42, 43): !result: [42, 43] -pa3(42, 43): !result: ['abcArgsPA3', 42, 43] -pa4(42, 43): !result: [42, 43] -sa(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa1(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa2(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa3(42, 43): !result: [['abcArgsPSA3', 42, 43], {'abcSelfPSA3': 'abcSelfPSA3Val'}] -psa4(42, 43): !result: [[42, 43], {'abcSelfPSA4': 'abcSelfPSA4Val'}] -a(42, self={"20": 1}): !result: [42] -pa1(42, self={"20": 1}): !result: ['abcArgsPA1', 42] -pa2(42, self={"20": 1}): !result: [42] -pa3(42, self={"20": 1}): !result: ['abcArgsPA3', 42] -pa4(42, self={"20": 1}): !result: [42] -sa(42, self={"20": 1}): !result: [[42], {'20': 1}] -psa1(42, self={"20": 1}): !result: [['abcArgsPSA1', 42], {'20': 1}] -psa2(42, self={"20": 1}): !result: [[42], {'20': 1}] -psa3(42, self={"20": 1}): !result: [['abcArgsPSA3', 42], {'20': 1}] -psa4(42, self={"20": 1}): !result: [[42], {'20': 1}] -a(self={"20": 1}): !result: [] -pa1(self={"20": 1}): !result: ['abcArgsPA1'] -pa2(self={"20": 1}): !result: [] -pa3(self={"20": 1}): !result: ['abcArgsPA3'] -pa4(self={"20": 1}): !result: [] -sa(self={"20": 1}): !result: [[], {'20': 1}] -psa1(self={"20": 1}): !result: [['abcArgsPSA1'], {'20': 1}] -psa2(self={"20": 1}): !result: [[], {'20': 1}] -psa3(self={"20": 1}): !result: [['abcArgsPSA3'], {'20': 1}] -psa4(self={"20": 1}): !result: [[], {'20': 1}] -a.args: None -pa1.args: ['abcArgsPA1'] -pa2.args: None -pa3.args: ['abcArgsPA3'] -pa4.args: None -sa.args: None -psa1.args: ['abcArgsPSA1'] -psa2.args: None -psa3.args: ['abcArgsPSA3'] -psa4.args: None -a.self: None -pa1.self: None -pa2.self: None -pa3.self: {'abcSelfPA3': 'abcSelfPA3Val'} -pa4.self: {'abcSelfPA4': 'abcSelfPA4Val'} -sa.self: None -psa1.self: None -psa2.self: None -psa3.self: {'abcSelfPSA3': 'abcSelfPSA3Val'} -psa4.self: {'abcSelfPSA4': 'abcSelfPSA4Val'} -a.name: 'Args' -pa1.name: 'Args' -pa2.name: 'Args' -pa3.name: 'Args' -pa4.name: 'Args' -sa.name: 'SelfArgs' -psa1.name: 'SelfArgs' -psa2.name: 'SelfArgs' -psa3.name: 'SelfArgs' -psa4.name: 'SelfArgs' -a.auto_rebind: 1 -pa1.auto_rebind: 1 -pa2.auto_rebind: 1 -pa3.auto_rebind: 0 -pa4.auto_rebind: 0 -sa.auto_rebind: 1 -psa1.auto_rebind: 1 -psa2.auto_rebind: 1 -psa3.auto_rebind: 0 -psa4.auto_rebind: 0 -psa5.auto_rebind: 0 -psa6.auto_rebind: 0 -psa7.auto_rebind: 1 -psa8.auto_rebind: 1 -psa9.auto_rebind: 1 -psaA.auto_rebind: 1 -psaB.auto_rebind: 1 -psaC.auto_rebind: 1 -' -abcdef -Error detected while processing function RunTest[]..Test: -line : -abcdef -abcA -line : -abcB' -['a', 'dup_a'] -['a', 'a'] -['a', 'b', 'c', 'C'] -[2, 2] -[2, 2] -1 -1 -function('Put') -testdir -test86.in -src -testdir/test86.in -testdir -test86.in -> Output ->> OutputSetattr -del sys.stdout.softspace:AttributeError:('cannot delete OutputObject attributes',) ->>> Testing NumberToLong using sys.stdout.softspace = %s -sys.stdout.softspace = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',) -sys.stdout.softspace = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',) -sys.stdout.softspace = -1:ValueError:('number must be greater or equal to zero',) -<<< Finished ->>> Testing NumberToLong using sys.stderr.softspace = %s -sys.stderr.softspace = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',) -sys.stderr.softspace = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',) -sys.stderr.softspace = -1:ValueError:('number must be greater or equal to zero',) -<<< Finished -assert sys.stdout.isatty()==False:NOT FAILED -assert sys.stdout.seekable()==False:NOT FAILED -sys.stdout.close():NOT FAILED -sys.stdout.flush():NOT FAILED -assert sys.stderr.isatty()==False:NOT FAILED -assert sys.stderr.seekable()==False:NOT FAILED -sys.stderr.close():NOT FAILED -sys.stderr.flush():NOT FAILED -sys.stdout.attr = None:AttributeError:('invalid attribute: attr',) ->> OutputWrite -assert sys.stdout.writable()==True:NOT FAILED -assert sys.stdout.readable()==False:NOT FAILED -assert sys.stderr.writable()==True:NOT FAILED -assert sys.stderr.readable()==False:NOT FAILED -assert sys.stdout.closed()==False:NOT FAILED -assert sys.stderr.closed()==False:NOT FAILED -assert sys.stdout.errors=="strict":NOT FAILED -assert sys.stderr.errors=="strict":NOT FAILED -assert sys.stdout.encoding==sys.stderr.encoding:NOT FAILED -sys.stdout.write(None):TypeError:('coercing to Unicode: need string or buffer, NoneType found',) ->> OutputWriteLines -sys.stdout.writelines(None):TypeError:("'NoneType' object is not iterable",) -sys.stdout.writelines([1]):TypeError:('coercing to Unicode: need string or buffer, int found',) ->>> Testing *Iter* using sys.stdout.writelines(%s) -sys.stdout.writelines(FailingIter()):NotImplementedError:('iter',) -sys.stdout.writelines(FailingIterNext()):NotImplementedError:('next',) -<<< Finished -> VimCommand ->>> Testing StringToChars using vim.command(%s) -vim.command(1):TypeError:('expected str() or unicode() instance, but got int',) -vim.command(u"\0"):TypeError:('expected string without null bytes',) -vim.command("\0"):TypeError:('expected string without null bytes',) -<<< Finished -vim.command("", 2):TypeError:('command() takes exactly one argument (2 given)',) -> VimToPython -> VimEval ->>> Testing StringToChars using vim.eval(%s) -vim.eval(1):TypeError:('expected str() or unicode() instance, but got int',) -vim.eval(u"\0"):TypeError:('expected string without null bytes',) -vim.eval("\0"):TypeError:('expected string without null bytes',) -<<< Finished -vim.eval("", FailingTrue()):TypeError:('function takes exactly 1 argument (2 given)',) -> VimEvalPy ->>> Testing StringToChars using vim.bindeval(%s) -vim.bindeval(1):TypeError:('expected str() or unicode() instance, but got int',) -vim.bindeval(u"\0"):TypeError:('expected string without null bytes',) -vim.bindeval("\0"):TypeError:('expected string without null bytes',) -<<< Finished -vim.eval("", 2):TypeError:('function takes exactly 1 argument (2 given)',) -> VimStrwidth ->>> Testing StringToChars using vim.strwidth(%s) -vim.strwidth(1):TypeError:('expected str() or unicode() instance, but got int',) -vim.strwidth(u"\0"):TypeError:('expected string without null bytes',) -vim.strwidth("\0"):TypeError:('expected string without null bytes',) -<<< Finished -> VimForeachRTP -vim.foreach_rtp(None):TypeError:("'NoneType' object is not callable",) -vim.foreach_rtp(NoArgsCall()):TypeError:('__call__() takes exactly 1 argument (2 given)',) -vim.foreach_rtp(FailingCall()):NotImplementedError:('call',) -vim.foreach_rtp(int, 2):TypeError:('foreach_rtp() takes exactly one argument (2 given)',) -> import -import xxx_no_such_module_xxx:ImportError:('No module named xxx_no_such_module_xxx',) -import failing_import:ImportError:() -import failing:NotImplementedError:() -> Options ->> OptionsItem -vim.options["abcQ"]:KeyError:('abcQ',) -vim.options[""]:ValueError:('empty keys are not allowed',) ->>> Testing StringToChars using vim.options[%s] -vim.options[1]:TypeError:('expected str() or unicode() instance, but got int',) -vim.options[u"\0"]:TypeError:('expected string without null bytes',) -vim.options["\0"]:TypeError:('expected string without null bytes',) -<<< Finished ->> OptionsContains ->>> Testing StringToChars using %s in vim.options -1 in vim.options:TypeError:('expected str() or unicode() instance, but got int',) -u"\0" in vim.options:TypeError:('expected string without null bytes',) -"\0" in vim.options:TypeError:('expected string without null bytes',) -<<< Finished -> Dictionary ->> DictionaryConstructor -vim.Dictionary("abcI"):ValueError:('expected sequence element of size 2, but got sequence of size 1',) ->> DictionarySetattr -del d.locked:AttributeError:('cannot delete vim.Dictionary attributes',) -d.locked = FailingTrue():NotImplementedError:('bool',) -vim.vvars.locked = False:TypeError:('cannot modify fixed dictionary',) -d.scope = True:AttributeError:('cannot set attribute scope',) -d.xxx = True:AttributeError:('cannot set attribute xxx',) ->> _DictionaryItem -d.get("a", 2, 3):TypeError:('function takes at most 2 arguments (3 given)',) ->>> Testing StringToChars using d.get(%s) -d.get(1):TypeError:('expected str() or unicode() instance, but got int',) -d.get(u"\0"):TypeError:('expected string without null bytes',) -d.get("\0"):TypeError:('expected string without null bytes',) -<<< Finished -d.pop("a"):KeyError:('a',) -dl.pop("a"):error:('dictionary is locked',) ->> DictionaryContains -"" in d:ValueError:('empty keys are not allowed',) -0 in d:TypeError:('expected str() or unicode() instance, but got int',) ->> DictionaryIterNext -for i in ned: ned["a"] = 1:RuntimeError:('hashtab changed during iteration',) ->> DictionaryAssItem -dl["b"] = 1:error:('dictionary is locked',) ->>> Testing StringToChars using d[%s] = 1 -d[1] = 1:TypeError:('expected str() or unicode() instance, but got int',) -d[u"\0"] = 1:TypeError:('expected string without null bytes',) -d["\0"] = 1:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d["a"] = {%s : 1} -d["a"] = {1 : 1}:TypeError:('expected str() or unicode() instance, but got int',) -d["a"] = {u"\0" : 1}:TypeError:('expected string without null bytes',) -d["a"] = {"\0" : 1}:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d["a"] = {"abcF" : {%s : 1}} -d["a"] = {"abcF" : {1 : 1}}:TypeError:('expected str() or unicode() instance, but got int',) -d["a"] = {"abcF" : {u"\0" : 1}}:TypeError:('expected string without null bytes',) -d["a"] = {"abcF" : {"\0" : 1}}:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d["a"] = {"abcF" : Mapping({%s : 1})} -d["a"] = {"abcF" : Mapping({1 : 1})}:TypeError:('expected str() or unicode() instance, but got int',) -d["a"] = {"abcF" : Mapping({u"\0" : 1})}:TypeError:('expected string without null bytes',) -d["a"] = {"abcF" : Mapping({"\0" : 1})}:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using d["a"] = {"abcF" : %s} -d["a"] = {"abcF" : FailingIter()}:TypeError:('unable to convert FailingIter to a Vim structure',) -d["a"] = {"abcF" : FailingIterNext()}:NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s} -d["a"] = {"abcF" : None}:NOT FAILED -d["a"] = {"abcF" : {"": 1}}:ValueError:('empty keys are not allowed',) -d["a"] = {"abcF" : {u"": 1}}:ValueError:('empty keys are not allowed',) -d["a"] = {"abcF" : FailingMapping()}:NotImplementedError:('keys',) -d["a"] = {"abcF" : FailingMappingKey()}:NotImplementedError:('getitem:mappingkey',) -d["a"] = {"abcF" : FailingNumber()}:TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using d["a"] = Mapping({%s : 1}) -d["a"] = Mapping({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',) -d["a"] = Mapping({u"\0" : 1}):TypeError:('expected string without null bytes',) -d["a"] = Mapping({"\0" : 1}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d["a"] = Mapping({"abcG" : {%s : 1}}) -d["a"] = Mapping({"abcG" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',) -d["a"] = Mapping({"abcG" : {u"\0" : 1}}):TypeError:('expected string without null bytes',) -d["a"] = Mapping({"abcG" : {"\0" : 1}}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d["a"] = Mapping({"abcG" : Mapping({%s : 1})}) -d["a"] = Mapping({"abcG" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',) -d["a"] = Mapping({"abcG" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',) -d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s}) -d["a"] = Mapping({"abcG" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) -d["a"] = Mapping({"abcG" : FailingIterNext()}):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s}) -d["a"] = Mapping({"abcG" : None}):NOT FAILED -d["a"] = Mapping({"abcG" : {"": 1}}):ValueError:('empty keys are not allowed',) -d["a"] = Mapping({"abcG" : {u"": 1}}):ValueError:('empty keys are not allowed',) -d["a"] = Mapping({"abcG" : FailingMapping()}):NotImplementedError:('keys',) -d["a"] = Mapping({"abcG" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',) -d["a"] = Mapping({"abcG" : FailingNumber()}):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using d["a"] = %s -d["a"] = FailingIter():TypeError:('unable to convert FailingIter to a Vim structure',) -d["a"] = FailingIterNext():NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d["a"] = %s -d["a"] = None:NOT FAILED -d["a"] = {"": 1}:ValueError:('empty keys are not allowed',) -d["a"] = {u"": 1}:ValueError:('empty keys are not allowed',) -d["a"] = FailingMapping():NotImplementedError:('keys',) -d["a"] = FailingMappingKey():NotImplementedError:('getitem:mappingkey',) -d["a"] = FailingNumber():TypeError:('long() argument must be a string or a number',) -<<< Finished ->> DictionaryUpdate ->>> kwargs ->>> iter -d.update(FailingMapping()):NotImplementedError:('keys',) -d.update([FailingIterNext()]):NotImplementedError:('next',) -d.update([FailingIterNextN(1)]):NotImplementedError:('next N',) ->>> Testing *Iter* using d.update(%s) -d.update(FailingIter()):NotImplementedError:('iter',) -d.update(FailingIterNext()):NotImplementedError:('next',) -<<< Finished ->>> Testing StringToChars using d.update({%s : 1}) -d.update({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',) -d.update({u"\0" : 1}):TypeError:('expected string without null bytes',) -d.update({"\0" : 1}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update({"abcF" : {%s : 1}}) -d.update({"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',) -d.update({"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',) -d.update({"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update({"abcF" : Mapping({%s : 1})}) -d.update({"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',) -d.update({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',) -d.update({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using d.update({"abcF" : %s}) -d.update({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) -d.update({"abcF" : FailingIterNext()}):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d.update({"abcF" : %s}) -d.update({"abcF" : None}):NOT FAILED -d.update({"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',) -d.update({"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',) -d.update({"abcF" : FailingMapping()}):NotImplementedError:('keys',) -d.update({"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',) -d.update({"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using d.update(Mapping({%s : 1})) -d.update(Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',) -d.update(Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',) -d.update(Mapping({"\0" : 1})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update(Mapping({"abcG" : {%s : 1}})) -d.update(Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',) -d.update(Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',) -d.update(Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update(Mapping({"abcG" : Mapping({%s : 1})})) -d.update(Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',) -d.update(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',) -d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using d.update(Mapping({"abcG" : %s})) -d.update(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to a Vim structure',) -d.update(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s})) -d.update(Mapping({"abcG" : None})):NOT FAILED -d.update(Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',) -d.update(Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',) -d.update(Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',) -d.update(Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',) -d.update(Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using d.update(%s) -d.update(FailingIter()):NotImplementedError:('iter',) -d.update(FailingIterNext()):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d.update(%s) -d.update(None):TypeError:("'NoneType' object is not iterable",) -d.update({"": 1}):ValueError:('empty keys are not allowed',) -d.update({u"": 1}):ValueError:('empty keys are not allowed',) -d.update(FailingMapping()):NotImplementedError:('keys',) -d.update(FailingMappingKey()):NotImplementedError:('getitem:mappingkey',) -d.update(FailingNumber()):TypeError:("'FailingNumber' object is not iterable",) -<<< Finished ->>> Testing StringToChars using d.update(((%s, 0),)) -d.update(((1, 0),)):TypeError:('expected str() or unicode() instance, but got int',) -d.update(((u"\0", 0),)):TypeError:('expected string without null bytes',) -d.update((("\0", 0),)):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update((("a", {%s : 1}),)) -d.update((("a", {1 : 1}),)):TypeError:('expected str() or unicode() instance, but got int',) -d.update((("a", {u"\0" : 1}),)):TypeError:('expected string without null bytes',) -d.update((("a", {"\0" : 1}),)):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update((("a", {"abcF" : {%s : 1}}),)) -d.update((("a", {"abcF" : {1 : 1}}),)):TypeError:('expected str() or unicode() instance, but got int',) -d.update((("a", {"abcF" : {u"\0" : 1}}),)):TypeError:('expected string without null bytes',) -d.update((("a", {"abcF" : {"\0" : 1}}),)):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update((("a", {"abcF" : Mapping({%s : 1})}),)) -d.update((("a", {"abcF" : Mapping({1 : 1})}),)):TypeError:('expected str() or unicode() instance, but got int',) -d.update((("a", {"abcF" : Mapping({u"\0" : 1})}),)):TypeError:('expected string without null bytes',) -d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using d.update((("a", {"abcF" : %s}),)) -d.update((("a", {"abcF" : FailingIter()}),)):TypeError:('unable to convert FailingIter to a Vim structure',) -d.update((("a", {"abcF" : FailingIterNext()}),)):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),)) -d.update((("a", {"abcF" : None}),)):error:("failed to add key 'a' to dictionary",) -d.update((("a", {"abcF" : {"": 1}}),)):ValueError:('empty keys are not allowed',) -d.update((("a", {"abcF" : {u"": 1}}),)):ValueError:('empty keys are not allowed',) -d.update((("a", {"abcF" : FailingMapping()}),)):NotImplementedError:('keys',) -d.update((("a", {"abcF" : FailingMappingKey()}),)):NotImplementedError:('getitem:mappingkey',) -d.update((("a", {"abcF" : FailingNumber()}),)):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using d.update((("a", Mapping({%s : 1})),)) -d.update((("a", Mapping({1 : 1})),)):TypeError:('expected str() or unicode() instance, but got int',) -d.update((("a", Mapping({u"\0" : 1})),)):TypeError:('expected string without null bytes',) -d.update((("a", Mapping({"\0" : 1})),)):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : {%s : 1}})),)) -d.update((("a", Mapping({"abcG" : {1 : 1}})),)):TypeError:('expected str() or unicode() instance, but got int',) -d.update((("a", Mapping({"abcG" : {u"\0" : 1}})),)):TypeError:('expected string without null bytes',) -d.update((("a", Mapping({"abcG" : {"\0" : 1}})),)):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : Mapping({%s : 1})})),)) -d.update((("a", Mapping({"abcG" : Mapping({1 : 1})})),)):TypeError:('expected str() or unicode() instance, but got int',) -d.update((("a", Mapping({"abcG" : Mapping({u"\0" : 1})})),)):TypeError:('expected string without null bytes',) -d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),)) -d.update((("a", Mapping({"abcG" : FailingIter()})),)):TypeError:('unable to convert FailingIter to a Vim structure',) -d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),)) -d.update((("a", Mapping({"abcG" : None})),)):error:("failed to add key 'a' to dictionary",) -d.update((("a", Mapping({"abcG" : {"": 1}})),)):ValueError:('empty keys are not allowed',) -d.update((("a", Mapping({"abcG" : {u"": 1}})),)):ValueError:('empty keys are not allowed',) -d.update((("a", Mapping({"abcG" : FailingMapping()})),)):NotImplementedError:('keys',) -d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):NotImplementedError:('getitem:mappingkey',) -d.update((("a", Mapping({"abcG" : FailingNumber()})),)):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using d.update((("a", %s),)) -d.update((("a", FailingIter()),)):TypeError:('unable to convert FailingIter to a Vim structure',) -d.update((("a", FailingIterNext()),)):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using d.update((("a", %s),)) -d.update((("a", None),)):error:("failed to add key 'a' to dictionary",) -d.update((("a", {"": 1}),)):ValueError:('empty keys are not allowed',) -d.update((("a", {u"": 1}),)):ValueError:('empty keys are not allowed',) -d.update((("a", FailingMapping()),)):NotImplementedError:('keys',) -d.update((("a", FailingMappingKey()),)):NotImplementedError:('getitem:mappingkey',) -d.update((("a", FailingNumber()),)):TypeError:('long() argument must be a string or a number',) -<<< Finished ->> DictionaryPopItem -d.popitem(1, 2):TypeError:('popitem() takes no arguments (2 given)',) ->> DictionaryHasKey -d.has_key():TypeError:('has_key() takes exactly one argument (0 given)',) -> List ->> ListConstructor -vim.List(1, 2):TypeError:('function takes at most 1 argument (2 given)',) -vim.List(a=1):TypeError:('list constructor does not accept keyword arguments',) ->>> Testing *Iter* using vim.List(%s) -vim.List(FailingIter()):NotImplementedError:('iter',) -vim.List(FailingIterNext()):NotImplementedError:('next',) -<<< Finished ->>> Testing StringToChars using vim.List([{%s : 1}]) -vim.List([{1 : 1}]):TypeError:('expected str() or unicode() instance, but got int',) -vim.List([{u"\0" : 1}]):TypeError:('expected string without null bytes',) -vim.List([{"\0" : 1}]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using vim.List([{"abcF" : {%s : 1}}]) -vim.List([{"abcF" : {1 : 1}}]):TypeError:('expected str() or unicode() instance, but got int',) -vim.List([{"abcF" : {u"\0" : 1}}]):TypeError:('expected string without null bytes',) -vim.List([{"abcF" : {"\0" : 1}}]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using vim.List([{"abcF" : Mapping({%s : 1})}]) -vim.List([{"abcF" : Mapping({1 : 1})}]):TypeError:('expected str() or unicode() instance, but got int',) -vim.List([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without null bytes',) -vim.List([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using vim.List([{"abcF" : %s}]) -vim.List([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to a Vim structure',) -vim.List([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}]) -vim.List([{"abcF" : None}]):NOT FAILED -vim.List([{"abcF" : {"": 1}}]):ValueError:('empty keys are not allowed',) -vim.List([{"abcF" : {u"": 1}}]):ValueError:('empty keys are not allowed',) -vim.List([{"abcF" : FailingMapping()}]):NotImplementedError:('keys',) -vim.List([{"abcF" : FailingMappingKey()}]):NotImplementedError:('getitem:mappingkey',) -vim.List([{"abcF" : FailingNumber()}]):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using vim.List([Mapping({%s : 1})]) -vim.List([Mapping({1 : 1})]):TypeError:('expected str() or unicode() instance, but got int',) -vim.List([Mapping({u"\0" : 1})]):TypeError:('expected string without null bytes',) -vim.List([Mapping({"\0" : 1})]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using vim.List([Mapping({"abcG" : {%s : 1}})]) -vim.List([Mapping({"abcG" : {1 : 1}})]):TypeError:('expected str() or unicode() instance, but got int',) -vim.List([Mapping({"abcG" : {u"\0" : 1}})]):TypeError:('expected string without null bytes',) -vim.List([Mapping({"abcG" : {"\0" : 1}})]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using vim.List([Mapping({"abcG" : Mapping({%s : 1})})]) -vim.List([Mapping({"abcG" : Mapping({1 : 1})})]):TypeError:('expected str() or unicode() instance, but got int',) -vim.List([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string without null bytes',) -vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})]) -vim.List([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to a Vim structure',) -vim.List([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})]) -vim.List([Mapping({"abcG" : None})]):NOT FAILED -vim.List([Mapping({"abcG" : {"": 1}})]):ValueError:('empty keys are not allowed',) -vim.List([Mapping({"abcG" : {u"": 1}})]):ValueError:('empty keys are not allowed',) -vim.List([Mapping({"abcG" : FailingMapping()})]):NotImplementedError:('keys',) -vim.List([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getitem:mappingkey',) -vim.List([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using vim.List([%s]) -vim.List([FailingIter()]):TypeError:('unable to convert FailingIter to a Vim structure',) -vim.List([FailingIterNext()]):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using vim.List([%s]) -vim.List([None]):NOT FAILED -vim.List([{"": 1}]):ValueError:('empty keys are not allowed',) -vim.List([{u"": 1}]):ValueError:('empty keys are not allowed',) -vim.List([FailingMapping()]):NotImplementedError:('keys',) -vim.List([FailingMappingKey()]):NotImplementedError:('getitem:mappingkey',) -vim.List([FailingNumber()]):TypeError:('long() argument must be a string or a number',) -<<< Finished ->> ListItem -l[1000]:IndexError:('list index out of range',) ->> ListAssItem -ll[1] = 2:error:('list is locked',) -l[1000] = 3:IndexError:('list index out of range',) ->> ListAssSlice -ll[1:100] = "abcJ":error:('list is locked',) ->>> Testing *Iter* using l[:] = %s -l[:] = FailingIter():NotImplementedError:('iter',) -l[:] = FailingIterNext():NotImplementedError:('next',) -<<< Finished -nel[1:10:2] = "abcK":ValueError:('attempt to assign sequence of size greater than 2 to extended slice',) -('a', 'b', 'c', 'O') -nel[1:10:2] = "a":ValueError:('attempt to assign sequence of size 1 to extended slice of size 2',) -('a', 'b', 'c', 'O') -nel[1:1:-1] = "a":ValueError:('attempt to assign sequence of size greater than 0 to extended slice',) -('a', 'b', 'c', 'O') -nel[:] = FailingIterNextN(2):NotImplementedError:('next N',) -('a', 'b', 'c', 'O') ->>> Testing StringToChars using l[:] = [{%s : 1}] -l[:] = [{1 : 1}]:TypeError:('expected str() or unicode() instance, but got int',) -l[:] = [{u"\0" : 1}]:TypeError:('expected string without null bytes',) -l[:] = [{"\0" : 1}]:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l[:] = [{"abcF" : {%s : 1}}] -l[:] = [{"abcF" : {1 : 1}}]:TypeError:('expected str() or unicode() instance, but got int',) -l[:] = [{"abcF" : {u"\0" : 1}}]:TypeError:('expected string without null bytes',) -l[:] = [{"abcF" : {"\0" : 1}}]:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l[:] = [{"abcF" : Mapping({%s : 1})}] -l[:] = [{"abcF" : Mapping({1 : 1})}]:TypeError:('expected str() or unicode() instance, but got int',) -l[:] = [{"abcF" : Mapping({u"\0" : 1})}]:TypeError:('expected string without null bytes',) -l[:] = [{"abcF" : Mapping({"\0" : 1})}]:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using l[:] = [{"abcF" : %s}] -l[:] = [{"abcF" : FailingIter()}]:TypeError:('unable to convert FailingIter to a Vim structure',) -l[:] = [{"abcF" : FailingIterNext()}]:NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}] -l[:] = [{"abcF" : None}]:NOT FAILED -l[:] = [{"abcF" : {"": 1}}]:ValueError:('empty keys are not allowed',) -l[:] = [{"abcF" : {u"": 1}}]:ValueError:('empty keys are not allowed',) -l[:] = [{"abcF" : FailingMapping()}]:NotImplementedError:('keys',) -l[:] = [{"abcF" : FailingMappingKey()}]:NotImplementedError:('getitem:mappingkey',) -l[:] = [{"abcF" : FailingNumber()}]:TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using l[:] = [Mapping({%s : 1})] -l[:] = [Mapping({1 : 1})]:TypeError:('expected str() or unicode() instance, but got int',) -l[:] = [Mapping({u"\0" : 1})]:TypeError:('expected string without null bytes',) -l[:] = [Mapping({"\0" : 1})]:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l[:] = [Mapping({"abcG" : {%s : 1}})] -l[:] = [Mapping({"abcG" : {1 : 1}})]:TypeError:('expected str() or unicode() instance, but got int',) -l[:] = [Mapping({"abcG" : {u"\0" : 1}})]:TypeError:('expected string without null bytes',) -l[:] = [Mapping({"abcG" : {"\0" : 1}})]:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l[:] = [Mapping({"abcG" : Mapping({%s : 1})})] -l[:] = [Mapping({"abcG" : Mapping({1 : 1})})]:TypeError:('expected str() or unicode() instance, but got int',) -l[:] = [Mapping({"abcG" : Mapping({u"\0" : 1})})]:TypeError:('expected string without null bytes',) -l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})] -l[:] = [Mapping({"abcG" : FailingIter()})]:TypeError:('unable to convert FailingIter to a Vim structure',) -l[:] = [Mapping({"abcG" : FailingIterNext()})]:NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})] -l[:] = [Mapping({"abcG" : None})]:NOT FAILED -l[:] = [Mapping({"abcG" : {"": 1}})]:ValueError:('empty keys are not allowed',) -l[:] = [Mapping({"abcG" : {u"": 1}})]:ValueError:('empty keys are not allowed',) -l[:] = [Mapping({"abcG" : FailingMapping()})]:NotImplementedError:('keys',) -l[:] = [Mapping({"abcG" : FailingMappingKey()})]:NotImplementedError:('getitem:mappingkey',) -l[:] = [Mapping({"abcG" : FailingNumber()})]:TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using l[:] = [%s] -l[:] = [FailingIter()]:TypeError:('unable to convert FailingIter to a Vim structure',) -l[:] = [FailingIterNext()]:NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using l[:] = [%s] -l[:] = [None]:NOT FAILED -l[:] = [{"": 1}]:ValueError:('empty keys are not allowed',) -l[:] = [{u"": 1}]:ValueError:('empty keys are not allowed',) -l[:] = [FailingMapping()]:NotImplementedError:('keys',) -l[:] = [FailingMappingKey()]:NotImplementedError:('getitem:mappingkey',) -l[:] = [FailingNumber()]:TypeError:('long() argument must be a string or a number',) -<<< Finished ->> ListConcatInPlace ->>> Testing *Iter* using l.extend(%s) -l.extend(FailingIter()):NotImplementedError:('iter',) -l.extend(FailingIterNext()):NotImplementedError:('next',) -<<< Finished ->>> Testing StringToChars using l.extend([{%s : 1}]) -l.extend([{1 : 1}]):TypeError:('expected str() or unicode() instance, but got int',) -l.extend([{u"\0" : 1}]):TypeError:('expected string without null bytes',) -l.extend([{"\0" : 1}]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l.extend([{"abcF" : {%s : 1}}]) -l.extend([{"abcF" : {1 : 1}}]):TypeError:('expected str() or unicode() instance, but got int',) -l.extend([{"abcF" : {u"\0" : 1}}]):TypeError:('expected string without null bytes',) -l.extend([{"abcF" : {"\0" : 1}}]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l.extend([{"abcF" : Mapping({%s : 1})}]) -l.extend([{"abcF" : Mapping({1 : 1})}]):TypeError:('expected str() or unicode() instance, but got int',) -l.extend([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without null bytes',) -l.extend([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using l.extend([{"abcF" : %s}]) -l.extend([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to a Vim structure',) -l.extend([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}]) -l.extend([{"abcF" : None}]):NOT FAILED -l.extend([{"abcF" : {"": 1}}]):ValueError:('empty keys are not allowed',) -l.extend([{"abcF" : {u"": 1}}]):ValueError:('empty keys are not allowed',) -l.extend([{"abcF" : FailingMapping()}]):NotImplementedError:('keys',) -l.extend([{"abcF" : FailingMappingKey()}]):NotImplementedError:('getitem:mappingkey',) -l.extend([{"abcF" : FailingNumber()}]):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using l.extend([Mapping({%s : 1})]) -l.extend([Mapping({1 : 1})]):TypeError:('expected str() or unicode() instance, but got int',) -l.extend([Mapping({u"\0" : 1})]):TypeError:('expected string without null bytes',) -l.extend([Mapping({"\0" : 1})]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l.extend([Mapping({"abcG" : {%s : 1}})]) -l.extend([Mapping({"abcG" : {1 : 1}})]):TypeError:('expected str() or unicode() instance, but got int',) -l.extend([Mapping({"abcG" : {u"\0" : 1}})]):TypeError:('expected string without null bytes',) -l.extend([Mapping({"abcG" : {"\0" : 1}})]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using l.extend([Mapping({"abcG" : Mapping({%s : 1})})]) -l.extend([Mapping({"abcG" : Mapping({1 : 1})})]):TypeError:('expected str() or unicode() instance, but got int',) -l.extend([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string without null bytes',) -l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})]) -l.extend([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to a Vim structure',) -l.extend([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})]) -l.extend([Mapping({"abcG" : None})]):NOT FAILED -l.extend([Mapping({"abcG" : {"": 1}})]):ValueError:('empty keys are not allowed',) -l.extend([Mapping({"abcG" : {u"": 1}})]):ValueError:('empty keys are not allowed',) -l.extend([Mapping({"abcG" : FailingMapping()})]):NotImplementedError:('keys',) -l.extend([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getitem:mappingkey',) -l.extend([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using l.extend([%s]) -l.extend([FailingIter()]):TypeError:('unable to convert FailingIter to a Vim structure',) -l.extend([FailingIterNext()]):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using l.extend([%s]) -l.extend([None]):NOT FAILED -l.extend([{"": 1}]):ValueError:('empty keys are not allowed',) -l.extend([{u"": 1}]):ValueError:('empty keys are not allowed',) -l.extend([FailingMapping()]):NotImplementedError:('keys',) -l.extend([FailingMappingKey()]):NotImplementedError:('getitem:mappingkey',) -l.extend([FailingNumber()]):TypeError:('long() argument must be a string or a number',) -<<< Finished ->> ListSetattr -del l.locked:AttributeError:('cannot delete vim.List attributes',) -l.locked = FailingTrue():NotImplementedError:('bool',) -l.xxx = True:AttributeError:('cannot set attribute xxx',) -> Function ->> FunctionConstructor ->>> FunctionConstructor -vim.Function("123"):ValueError:('unnamed function 123 does not exist',) -vim.Function("xxx_non_existent_function_xxx"):ValueError:('function xxx_non_existent_function_xxx does not exist',) -vim.Function("xxx#non#existent#function#xxx"):NOT FAILED -vim.Function("xxx_non_existent_function_xxx2", args=[]):ValueError:('function xxx_non_existent_function_xxx2 does not exist',) -vim.Function("xxx_non_existent_function_xxx3", self={}):ValueError:('function xxx_non_existent_function_xxx3 does not exist',) -vim.Function("xxx_non_existent_function_xxx4", args=[], self={}):ValueError:('function xxx_non_existent_function_xxx4 does not exist',) ->>> FunctionNew -vim.Function("tr", self="abcFuncSelf"):TypeError:('unable to convert str to a Vim dictionary',) -vim.Function("tr", args=427423):TypeError:('unable to convert int to a Vim list',) -vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to a Vim dictionary',) -vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to a Vim dictionary',) -vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to a Vim dictionary',) -vim.Function("tr", ""):TypeError:('function takes exactly 1 argument (2 given)',) ->> FunctionCall ->>> Testing StringToChars using f({%s : 1}) -f({1 : 1}):TypeError:('expected str() or unicode() instance, but got int',) -f({u"\0" : 1}):TypeError:('expected string without null bytes',) -f({"\0" : 1}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using f({"abcF" : {%s : 1}}) -f({"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',) -f({"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',) -f({"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using f({"abcF" : Mapping({%s : 1})}) -f({"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',) -f({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',) -f({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using f({"abcF" : %s}) -f({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) -f({"abcF" : FailingIterNext()}):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using f({"abcF" : %s}) -f({"abcF" : None}):NOT FAILED -f({"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',) -f({"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',) -f({"abcF" : FailingMapping()}):NotImplementedError:('keys',) -f({"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',) -f({"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using f(Mapping({%s : 1})) -f(Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',) -f(Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',) -f(Mapping({"\0" : 1})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using f(Mapping({"abcG" : {%s : 1}})) -f(Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',) -f(Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',) -f(Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using f(Mapping({"abcG" : Mapping({%s : 1})})) -f(Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',) -f(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',) -f(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using f(Mapping({"abcG" : %s})) -f(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to a Vim structure',) -f(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s})) -f(Mapping({"abcG" : None})):NOT FAILED -f(Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',) -f(Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',) -f(Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',) -f(Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',) -f(Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using f(%s) -f(FailingIter()):TypeError:('unable to convert FailingIter to a Vim structure',) -f(FailingIterNext()):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using f(%s) -f(None):NOT FAILED -f({"": 1}):ValueError:('empty keys are not allowed',) -f({u"": 1}):ValueError:('empty keys are not allowed',) -f(FailingMapping()):NotImplementedError:('keys',) -f(FailingMappingKey()):NotImplementedError:('getitem:mappingkey',) -f(FailingNumber()):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using fd(self={%s : 1}) -fd(self={1 : 1}):TypeError:('expected str() or unicode() instance, but got int',) -fd(self={u"\0" : 1}):TypeError:('expected string without null bytes',) -fd(self={"\0" : 1}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using fd(self={"abcF" : {%s : 1}}) -fd(self={"abcF" : {1 : 1}}):TypeError:('expected str() or unicode() instance, but got int',) -fd(self={"abcF" : {u"\0" : 1}}):TypeError:('expected string without null bytes',) -fd(self={"abcF" : {"\0" : 1}}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using fd(self={"abcF" : Mapping({%s : 1})}) -fd(self={"abcF" : Mapping({1 : 1})}):TypeError:('expected str() or unicode() instance, but got int',) -fd(self={"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null bytes',) -fd(self={"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using fd(self={"abcF" : %s}) -fd(self={"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) -fd(self={"abcF" : FailingIterNext()}):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using fd(self={"abcF" : %s}) -fd(self={"abcF" : None}):NOT FAILED -fd(self={"abcF" : {"": 1}}):ValueError:('empty keys are not allowed',) -fd(self={"abcF" : {u"": 1}}):ValueError:('empty keys are not allowed',) -fd(self={"abcF" : FailingMapping()}):NotImplementedError:('keys',) -fd(self={"abcF" : FailingMappingKey()}):NotImplementedError:('getitem:mappingkey',) -fd(self={"abcF" : FailingNumber()}):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing StringToChars using fd(self=Mapping({%s : 1})) -fd(self=Mapping({1 : 1})):TypeError:('expected str() or unicode() instance, but got int',) -fd(self=Mapping({u"\0" : 1})):TypeError:('expected string without null bytes',) -fd(self=Mapping({"\0" : 1})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using fd(self=Mapping({"abcG" : {%s : 1}})) -fd(self=Mapping({"abcG" : {1 : 1}})):TypeError:('expected str() or unicode() instance, but got int',) -fd(self=Mapping({"abcG" : {u"\0" : 1}})):TypeError:('expected string without null bytes',) -fd(self=Mapping({"abcG" : {"\0" : 1}})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing StringToChars using fd(self=Mapping({"abcG" : Mapping({%s : 1})})) -fd(self=Mapping({"abcG" : Mapping({1 : 1})})):TypeError:('expected str() or unicode() instance, but got int',) -fd(self=Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without null bytes',) -fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',) -<<< Finished ->>> Testing *Iter* using fd(self=Mapping({"abcG" : %s})) -fd(self=Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to a Vim structure',) -fd(self=Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',) -<<< Finished ->>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s})) -fd(self=Mapping({"abcG" : None})):NOT FAILED -fd(self=Mapping({"abcG" : {"": 1}})):ValueError:('empty keys are not allowed',) -fd(self=Mapping({"abcG" : {u"": 1}})):ValueError:('empty keys are not allowed',) -fd(self=Mapping({"abcG" : FailingMapping()})):NotImplementedError:('keys',) -fd(self=Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mappingkey',) -fd(self=Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',) -<<< Finished ->>> Testing *Iter* using fd(self=%s) -fd(self=FailingIter()):TypeError:('unable to convert FailingIter to a Vim dictionary',) -fd(self=FailingIterNext()):TypeError:('unable to convert FailingIterNext to a Vim dictionary',) -<<< Finished ->>> Testing ConvertFromPyObject using fd(self=%s) -fd(self=None):TypeError:('unable to convert NoneType to a Vim dictionary',) -fd(self={"": 1}):ValueError:('empty keys are not allowed',) -fd(self={u"": 1}):ValueError:('empty keys are not allowed',) -fd(self=FailingMapping()):NotImplementedError:('keys',) -fd(self=FailingMappingKey()):NotImplementedError:('getitem:mappingkey',) -fd(self=FailingNumber()):TypeError:('unable to convert FailingNumber to a Vim dictionary',) -<<< Finished ->>> Testing ConvertFromPyMapping using fd(self=%s) -fd(self=[]):TypeError:('unable to convert list to a Vim dictionary',) -<<< Finished -> TabPage ->> TabPageAttr -vim.current.tabpage.xxx:AttributeError:('xxx',) -> TabList ->> TabListItem -vim.tabpages[1000]:IndexError:('no such tab page',) -> Window ->> WindowAttr -vim.current.window.xxx:AttributeError:('xxx',) ->> WindowSetattr -vim.current.window.buffer = 0:TypeError:('readonly attribute: buffer',) -vim.current.window.cursor = (100000000, 100000000):error:('cursor position outside buffer',) -vim.current.window.cursor = True:TypeError:('argument must be 2-item sequence, not bool',) ->>> Testing NumberToLong using vim.current.window.height = %s -vim.current.window.height = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',) -vim.current.window.height = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',) -vim.current.window.height = -1:ValueError:('number must be greater or equal to zero',) -<<< Finished ->>> Testing NumberToLong using vim.current.window.width = %s -vim.current.window.width = []:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',) -vim.current.window.width = None:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',) -vim.current.window.width = -1:ValueError:('number must be greater or equal to zero',) -<<< Finished -vim.current.window.xxxxxx = True:AttributeError:('xxxxxx',) -> WinList ->> WinListItem -vim.windows[1000]:IndexError:('no such window',) -> Buffer ->> StringToLine (indirect) -vim.current.buffer[0] = u"\na":error:('string cannot contain newlines',) -vim.current.buffer[0] = "\na":error:('string cannot contain newlines',) ->> SetBufferLine (indirect) -vim.current.buffer[0] = True:TypeError:('bad argument type for built-in operation',) ->> SetBufferLineList (indirect) -vim.current.buffer[:] = True:TypeError:('bad argument type for built-in operation',) -vim.current.buffer[:] = ["\na", "bc"]:error:('string cannot contain newlines',) ->> InsertBufferLines (indirect) -vim.current.buffer.append(None):TypeError:('bad argument type for built-in operation',) -vim.current.buffer.append(["\na", "bc"]):error:('string cannot contain newlines',) -vim.current.buffer.append("\nbc"):error:('string cannot contain newlines',) ->> RBItem -vim.current.buffer[100000000]:IndexError:('line number out of range',) ->> RBAsItem -vim.current.buffer[100000000] = "":IndexError:('line number out of range',) ->> BufferAttr -vim.current.buffer.xxx:AttributeError:('xxx',) ->> BufferSetattr -vim.current.buffer.name = True:TypeError:('expected str() or unicode() instance, but got bool',) -vim.current.buffer.xxx = True:AttributeError:('xxx',) ->> BufferMark -vim.current.buffer.mark(0):TypeError:('expected str() or unicode() instance, but got int',) -vim.current.buffer.mark("abcM"):ValueError:('mark name must be a single character',) -vim.current.buffer.mark("!"):error:('invalid mark name',) ->> BufferRange -vim.current.buffer.range(1, 2, 3):TypeError:('function takes exactly 2 arguments (3 given)',) -> BufMap ->> BufMapItem -vim.buffers[100000000]:KeyError:(100000000,) ->>> Testing NumberToLong using vim.buffers[%s] -vim.buffers[[]]:TypeError:('expected int(), long() or something supporting coercing to long(), but got list',) -vim.buffers[None]:TypeError:('expected int(), long() or something supporting coercing to long(), but got NoneType',) -vim.buffers[-1]:ValueError:('number must be greater than zero',) -vim.buffers[0]:ValueError:('number must be greater than zero',) -<<< Finished -> Current ->> CurrentGetattr -vim.current.xxx:AttributeError:('xxx',) ->> CurrentSetattr -vim.current.line = True:TypeError:('bad argument type for built-in operation',) -vim.current.buffer = True:TypeError:('expected vim.Buffer object, but got bool',) -vim.current.window = True:TypeError:('expected vim.Window object, but got bool',) -vim.current.tabpage = True:TypeError:('expected vim.TabPage object, but got bool',) -vim.current.xxx = True:AttributeError:('xxx',) -['/testdir'] -'/testdir' -2,xx -before -after -pythonx/topmodule/__init__.py -pythonx/topmodule/submodule/__init__.py -pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py -vim.command("throw 'abcN'"):error:('abcN',) -Exe("throw 'def'"):error:('def',) -vim.eval("Exe('throw ''ghi''')"):error:('ghi',) -vim.eval("Exe('echoerr ''jkl''')"):error:('Vim(echoerr):jkl',) -vim.eval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',) -vim.eval("xxx_unknown_function_xxx()"):error:('Vim:E117: Unknown function: xxx_unknown_function_xxx',) -vim.bindeval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',) -Caught KeyboardInterrupt -Running :put -No exception - diff --git a/src/testdir/test87.in b/src/testdir/test87.in deleted file mode 100644 index 187b80760f..0000000000 --- a/src/testdir/test87.in +++ /dev/null @@ -1,1725 +0,0 @@ -Tests for various python features. vim: set ft=vim : - -STARTTEST -:so small.vim -:set noswapfile -:if !has('python3') || !has('quickfix') | e! test.ok | wq! test.out | endif -:lang C -:fun Test() -:py3 import vim -:py3 cb = vim.current.buffer -:let l = [] -:py3 l=vim.bindeval('l') -:py3 f=vim.bindeval('function("strlen")') -:" Extending List directly with different types -:py3 l+=[1, "as'd", [1, 2, f, {'a': 1}]] -:$put =string(l) -:$put =string(l[-1]) -:try -: $put =string(l[-4]) -:catch -: $put =v:exception[:13] -:endtry -:" List assignment -:py3 l[0]=0 -:$put =string(l) -:py3 l[-2]=f -:$put =string(l) -:" -:" Extending Dictionary directly with different types -:let d = {} -:fun d.f() -: return 1 -:endfun -py3 << trim EOF - d=vim.bindeval('d') - d['1']='asd' - d.update() # Must not do anything, including throwing errors - d.update(b=[1, 2, f]) - d.update((('-1', {'a': 1}),)) - d.update({'0': -1}) - dk = d.keys() - dv = d.values() - di = d.items() - dk.sort(key=repr) - dv.sort(key=repr) - di.sort(key=repr) -EOF -:$put =py3eval('d[''f''](self={})') -:$put =py3eval('repr(dk)') -:$put =substitute(py3eval('repr(dv)'),'0x\x\+','','g') -:$put =substitute(py3eval('repr(di)'),'0x\x\+','','g') -:for [key, Val] in sort(items(d)) -: $put =string(key) . ' : ' . string(Val) -: unlet key Val -:endfor -:py3 del dk -:py3 del di -:py3 del dv -:" -:" removing items with del -:py3 del l[2] -:$put =string(l) -:let l = range(8) -:py3 l=vim.bindeval('l') -:try -: py3 del l[:3] -: py3 del l[1:] -:catch -: $put =v:exception -:endtry -:$put =string(l) -:" -:py3 del d['-1'] -:py3 del d['f'] -:$put =string(py3eval('d.get(''b'', 1)')) -:$put =string(py3eval('d.pop(''b'')')) -:$put =string(py3eval('d.get(''b'', 1)')) -:$put =string(py3eval('d.pop(''1'', 2)')) -:$put =string(py3eval('d.pop(''1'', 2)')) -:$put =py3eval('repr(d.has_key(''0''))') -:$put =py3eval('repr(d.has_key(''1''))') -:$put =py3eval('repr(''0'' in d)') -:$put =py3eval('repr(''1'' in d)') -:$put =py3eval('repr(list(iter(d)))') -:$put =string(d) -:$put =py3eval('repr(d.popitem())') -:$put =py3eval('repr(d.get(''0''))') -:$put =py3eval('repr(list(iter(d)))') -:" -:" removing items out of range: silently skip items that don't exist -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:" The following two ranges delete nothing as they match empty list: -:py3 del l[2:1] -:$put =string(l) -:py3 del l[2:2] -:$put =string(l) -:py3 del l[2:3] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[2:4] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[2:5] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[2:6] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:" The following two ranges delete nothing as they match empty list: -:py3 del l[-1:2] -:$put =string(l) -:py3 del l[-2:2] -:$put =string(l) -:py3 del l[-3:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[-4:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[-5:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[-6:2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[::2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[3:0:-2] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 del l[2:4:-2] -:$put =string(l) -:" -:" Slice assignment to a list -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 l[0:0]=['a'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 l[1:2]=['b'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 l[2:4]=['c'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 l[4:4]=['d'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 l[-1:2]=['e'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 l[-10:2]=['f'] -:$put =string(l) -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:py3 l[2:-10]=['g'] -:$put =string(l) -:let l = [] -:py3 l=vim.bindeval('l') -:py3 l[0:0]=['h'] -:$put =string(l) -:let l = range(8) -:py3 l=vim.bindeval('l') -:py3 l[2:6:2] = [10, 20] -:$put =string(l) -:let l = range(8) -:py3 l=vim.bindeval('l') -:py3 l[6:2:-2] = [10, 20] -:$put =string(l) -:let l = range(8) -:py3 l=vim.bindeval('l') -:py3 l[6:2] = () -:$put =string(l) -:let l = range(8) -:py3 l=vim.bindeval('l') -:py3 l[6:2:1] = () -:$put =string(l) -:let l = range(8) -:py3 l=vim.bindeval('l') -:py3 l[2:2:1] = () -:$put =string(l) -:" -:" Locked variables -:let l = [0, 1, 2, 3] -:py3 l=vim.bindeval('l') -:lockvar! l -py3 << trim EOF - def emsg(ei): - return ei[0].__name__ + ':' + repr(ei[1].args) - - try: - l[2]='i' - except vim.error: - cb.append('l[2] threw vim.error: ' + emsg(sys.exc_info())) -EOF -:$put =string(l) -:unlockvar! l -:" -:" Function calls -py3 << trim EOF - import sys - import re - - py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$') - py37_exception_repr = re.compile(r'([^\(\),])(\)+)$') - - def ee(expr, g=globals(), l=locals()): - cb = vim.current.buffer - try: - try: - exec(expr, g, l) - except Exception as e: - if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."): - msg = repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))) - elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0: - msg = repr((e.__class__, ImportError(str(e).replace("'", '')))) - elif sys.version_info >= (3, 6) and e.__class__ is ModuleNotFoundError: - # Python 3.6 gives ModuleNotFoundError, change it to an ImportError - msg = repr((ImportError, ImportError(str(e).replace("'", '')))) - elif sys.version_info >= (3, 3) and e.__class__ is TypeError: - m = py33_type_error_pattern.search(str(e)) - if m: - msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2)) - msg = repr((e.__class__, TypeError(msg))) - else: - msg = repr((e.__class__, e)) - # Messages changed with Python 3.6, change new to old. - newmsg1 = """'argument must be str, bytes or bytearray, not None'""" - oldmsg1 = '''"Can't convert 'NoneType' object to str implicitly"''' - if msg.find(newmsg1) > -1: - msg = msg.replace(newmsg1, oldmsg1) - newmsg2 = """'argument must be str, bytes or bytearray, not int'""" - oldmsg2 = '''"Can't convert 'int' object to str implicitly"''' - if msg.find(newmsg2) > -1: - msg = msg.replace(newmsg2, oldmsg2) - elif sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte': - msg = repr((TypeError, TypeError('expected bytes with no null'))) - else: - msg = repr((e.__class__, e)) - # Some Python versions say can't, others cannot. - if msg.find('can\'t') > -1: - msg = msg.replace('can\'t', 'cannot') - # Some Python versions use single quote, some double quote - if msg.find('"cannot ') > -1: - msg = msg.replace('"cannot ', '\'cannot ') - if msg.find(' attributes"') > -1: - msg = msg.replace(' attributes"', ' attributes\'') - if sys.version_info >= (3, 7): - msg = py37_exception_repr.sub(r'\1,\2', msg) - cb.append(expr + ':' + msg) - else: - cb.append(expr + ':NOT FAILED') - except Exception as e: - msg = repr((e.__class__, e)) - if sys.version_info >= (3, 7): - msg = py37_exception_repr.sub(r'\1,\2', msg) - cb.append(expr + '::' + msg) -EOF -:fun New(...) -: return ['NewStart']+a:000+['NewEnd'] -:endfun -:fun DictNew(...) dict -: return ['DictNewStart']+a:000+['DictNewEnd', self] -:endfun -:let l=[function('New'), function('DictNew')] -:py3 l=vim.bindeval('l') -:py3 l.extend(list(l[0](1, 2, 3))) -:$put =string(l) -:py3 l.extend(list(l[1](1, 2, 3, self={'a': 'b'}))) -:$put =string(l) -:py3 l+=[l[0].name] -:$put =string(l) -:py3 ee('l[1](1, 2, 3)') -:py3 f=l[0] -:delfunction New -:py3 ee('f(1, 2, 3)') -:if has('float') -: let l=[0.0] -: py3 l=vim.bindeval('l') -: py3 l.extend([0.0]) -: $put =string(l) -:else -: $put ='[0.0, 0.0]' -:endif -:let messages=[] -:delfunction DictNew -py3 << trim EOF - import sys - d=vim.bindeval('{}') - m=vim.bindeval('messages') - def em(expr, g=globals(), l=locals()): - try: - exec(expr, g, l) - except Exception as e: - if sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte': - m.extend([TypeError.__name__]) - else: - m.extend([e.__class__.__name__]) - - em('d["abc1"]') - em('d["abc1"]="\\0"') - em('d["abc1"]=vim') - em('d[""]=1') - em('d["a\\0b"]=1') - em('d[b"a\\0b"]=1') - - em('d.pop("abc1")') - em('d.popitem()') - del em - del m -EOF -:$put =messages -:unlet messages -:" locked and scope attributes -:let d={} | let dl={} | lockvar dl -:for s in split("d dl v: g:") -: let name=tr(s, ':', 's') -: execute 'py3 '.name.'=vim.bindeval("'.s.'")' -: let toput=s.' : '.join(map(['locked', 'scope'], 'v:val.":".py3eval(name.".".v:val)'), ';') -: $put =toput -:endfor -:silent! let d.abc2=1 -:silent! let dl.abc3=1 -:py3 d.locked=True -:py3 dl.locked=False -:silent! let d.def=1 -:silent! let dl.def=1 -:put ='d:'.string(d) -:put ='dl:'.string(dl) -:unlet d dl -: -:let l=[] | let ll=[] | lockvar ll -:for s in split("l ll") -: let name=tr(s, ':', 's') -: execute 'py3 '.name.'=vim.bindeval("'.s.'")' -: let toput=s.' : locked:'.py3eval(name.'.locked') -: $put =toput -:endfor -:silent! call extend(l, [0]) -:silent! call extend(ll, [0]) -:py3 l.locked=True -:py3 ll.locked=False -:silent! call extend(l, [1]) -:silent! call extend(ll, [1]) -:put ='l:'.string(l) -:put ='ll:'.string(ll) -:unlet l ll -:" -:" py3eval() -:let l=py3eval('[0, 1, 2]') -:$put =string(l) -:let d=py3eval('{"a": "b", "c": 1, "d": ["e"]}') -:$put =sort(items(d)) -:let v:errmsg = '' -:$put ='py3eval(\"None\") = ' . py3eval('None') . v:errmsg -:if has('float') -: let f=py3eval('0.0') -: $put =string(f) -:else -: $put ='0.0' -:endif -:" Invalid values: -:for e in ['"\0"', '{"\0": 1}', 'undefined_name', 'vim'] -: try -: let v=py3eval(e) -: catch -: let toput=e.":\t".v:exception[:13] -: $put =toput -: endtry -:endfor -:" -:" threading -:let l = [0] -:py3 l=vim.bindeval('l') -py3 << trim EOF - import threading - import time - - class T(threading.Thread): - def __init__(self): - threading.Thread.__init__(self) - self.t = 0 - self.running = True - - def run(self): - while self.running: - self.t += 1 - time.sleep(0.1) - - t = T() - del T - t.start() -EOF -:sleep 1 -:py3 t.running = False -:py3 t.join() -:" Check if the background thread is working. Count should be 10, but on a -:" busy system (AppVeyor) it can be much lower. -:py3 l[0] = t.t > 4 -:py3 del time -:py3 del threading -:py3 del t -:$put =string(l) -:" -:" settrace -:let l = [] -:py3 l=vim.bindeval('l') -py3 << trim EOF - import sys - - def traceit(frame, event, arg): - global l - if event == "line": - l += [frame.f_lineno] - return traceit - - def trace_main(): - for i in range(5): - pass -EOF -:py3 sys.settrace(traceit) -:py3 trace_main() -:py3 sys.settrace(None) -:py3 del traceit -:py3 del trace_main -:$put =string(l) -:" -:" Slice -:py3 ll = vim.bindeval('[0, 1, 2, 3, 4, 5]') -:py3 l = ll[:4] -:$put =string(py3eval('l')) -:py3 l = ll[2:] -:$put =string(py3eval('l')) -:py3 l = ll[:-4] -:$put =string(py3eval('l')) -:py3 l = ll[-2:] -:$put =string(py3eval('l')) -:py3 l = ll[2:4] -:$put =string(py3eval('l')) -:py3 l = ll[4:2] -:$put =string(py3eval('l')) -:py3 l = ll[-4:-2] -:$put =string(py3eval('l')) -:py3 l = ll[-2:-4] -:$put =string(py3eval('l')) -:py3 l = ll[:] -:$put =string(py3eval('l')) -:py3 l = ll[0:6] -:$put =string(py3eval('l')) -:py3 l = ll[-10:10] -:$put =string(py3eval('l')) -:py3 l = ll[4:2:-1] -:$put =string(py3eval('l')) -:py3 l = ll[::2] -:$put =string(py3eval('l')) -:py3 l = ll[4:2:1] -:$put =string(py3eval('l')) -:py3 del l -:" -:" Vars -:let g:foo = 'bac' -:let w:abc3 = 'def' -:let b:baz = 'bar' -:let t:bar = 'jkl' -:try -: throw "Abc" -:catch -: put =py3eval('vim.vvars[''exception'']') -:endtry -:put =py3eval('vim.vars[''foo'']') -:put =py3eval('vim.current.window.vars[''abc3'']') -:put =py3eval('vim.current.buffer.vars[''baz'']') -:put =py3eval('vim.current.tabpage.vars[''bar'']') -:" -:" Options -:" paste: boolean, global -:" previewheight number, global -:" operatorfunc: string, global -:" number: boolean, window-local -:" numberwidth: number, window-local -:" colorcolumn: string, window-local -:" statusline: string, window-local/global -:" autoindent: boolean, buffer-local -:" shiftwidth: number, buffer-local -:" omnifunc: string, buffer-local -:" preserveindent: boolean, buffer-local/global -:" path: string, buffer-local/global -:let g:bufs=[bufnr('%')] -:new -:let g:bufs+=[bufnr('%')] -:vnew -:let g:bufs+=[bufnr('%')] -:wincmd j -:vnew -:let g:bufs+=[bufnr('%')] -:wincmd l -:fun RecVars(opt) -: let gval =string(eval('&g:'.a:opt)) -: let wvals=join(map(range(1, 4), 'v:val.":".string(getwinvar(v:val, "&".a:opt))')) -: let bvals=join(map(copy(g:bufs), 'v:val.":".string(getbufvar(v:val, "&".a:opt))')) -: put =' G: '.gval -: put =' W: '.wvals -: put =' B: '.wvals -:endfun -py3 << trim EOF - def e(s, g=globals(), l=locals()): - try: - exec(s, g, l) - except Exception as e: - vim.command('return ' + repr(e.__class__.__name__)) - - def ev(s, g=globals(), l=locals()): - try: - return eval(s, g, l) - except Exception as e: - vim.command('let exc=' + repr(e.__class__.__name__)) - return 0 -EOF -:fun E(s) -: python3 e(vim.eval('a:s')) -:endfun -:fun Ev(s) -: let r=py3eval('ev(vim.eval("a:s"))') -: if exists('exc') -: throw exc -: endif -: return r -:endfun -:py3 gopts1=vim.options -:py3 wopts1=vim.windows[2].options -:py3 wopts2=vim.windows[0].options -:py3 wopts3=vim.windows[1].options -:py3 bopts1=vim.buffers[vim.bindeval("g:bufs")[2]].options -:py3 bopts2=vim.buffers[vim.bindeval("g:bufs")[1]].options -:py3 bopts3=vim.buffers[vim.bindeval("g:bufs")[0]].options -:$put ='wopts iters equal: '.py3eval('list(wopts1) == list(wopts2)') -:$put ='bopts iters equal: '.py3eval('list(bopts1) == list(bopts2)') -:py3 gset=set(iter(gopts1)) -:py3 wset=set(iter(wopts1)) -:py3 bset=set(iter(bopts1)) -:set path=.,..,, -:let lst=[] -:let lst+=[['paste', 1, 0, 1, 2, 1, 1, 0 ]] -:let lst+=[['previewheight', 5, 1, 6, 'a', 0, 1, 0 ]] -:let lst+=[['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0 ]] -:let lst+=[['number', 0, 1, 1, 0, 1, 0, 1 ]] -:let lst+=[['numberwidth', 2, 3, 5, -100, 0, 0, 1 ]] -:let lst+=[['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1 ]] -:let lst+=[['statusline', '1', '2', '4', 0, 0, 1, 1 ]] -:let lst+=[['autoindent', 0, 1, 1, 2, 1, 0, 2 ]] -:let lst+=[['shiftwidth', 0, 2, 1, 3, 0, 0, 2 ]] -:let lst+=[['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2 ]] -:let lst+=[['preserveindent', 0, 1, 1, 2, 1, 1, 2 ]] -:let lst+=[['path', '.,,', ',,', '.', 0, 0, 1, 2 ]] -:for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst -: py3 oname=vim.eval('oname') -: py3 oval1=vim.bindeval('oval1') -: py3 oval2=vim.bindeval('oval2') -: py3 oval3=vim.bindeval('oval3') -: if invval is 0 || invval is 1 -: py3 invval=bool(vim.bindeval('invval')) -: else -: py3 invval=vim.bindeval('invval') -: endif -: if bool -: py3 oval1=bool(oval1) -: py3 oval2=bool(oval2) -: py3 oval3=bool(oval3) -: endif -: put ='>>> '.oname -: $put =' g/w/b:'.py3eval('oname in gset').'/'.py3eval('oname in wset').'/'.py3eval('oname in bset') -: $put =' g/w/b (in):'.py3eval('oname in gopts1').'/'.py3eval('oname in wopts1').'/'.py3eval('oname in bopts1') -: for v in ['gopts1', 'wopts1', 'bopts1'] -: try -: put =' p/'.v.': '.Ev('repr('.v.'['''.oname.'''])') -: catch -: put =' p/'.v.'! '.v:exception -: endtry -: let r=E(v.'['''.oname.''']=invval') -: if r isnot 0 -: put =' inv: '.string(invval).'! '.r -: endif -: for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3']) -: let val=substitute(vv, '^.opts', 'oval', '') -: let r=E(vv.'['''.oname.''']='.val) -: if r isnot 0 -: put =' '.vv.'! '.r -: endif -: endfor -: endfor -: call RecVars(oname) -: for v in ['wopts3', 'bopts3'] -: let r=E('del '.v.'["'.oname.'"]') -: if r isnot 0 -: put =' del '.v.'! '.r -: endif -: endfor -: call RecVars(oname) -:endfor -:delfunction RecVars -:delfunction E -:delfunction Ev -:py3 del ev -:py3 del e -:only -:for buf in g:bufs[1:] -: execute 'bwipeout!' buf -:endfor -:py3 del gopts1 -:py3 del wopts1 -:py3 del wopts2 -:py3 del wopts3 -:py3 del bopts1 -:py3 del bopts2 -:py3 del bopts3 -:py3 del oval1 -:py3 del oval2 -:py3 del oval3 -:py3 del oname -:py3 del invval -:" -:" Test buffer object -:vnew -:put ='First line' -:put ='Second line' -:put ='Third line' -:1 delete _ -:py3 b=vim.current.buffer -:wincmd w -:mark a -:augroup BUFS -: autocmd BufFilePost * python3 cb.append(vim.eval('expand("")') + ':BufFilePost:' + vim.eval('bufnr("%")')) -: autocmd BufFilePre * python3 cb.append(vim.eval('expand("")') + ':BufFilePre:' + vim.eval('bufnr("%")')) -:augroup END -py3 << trim EOF - # Tests BufferAppend and BufferItem - cb.append(b[0]) - # Tests BufferSlice and BufferAssSlice - cb.append('abc5') # Will be overwritten - cb[-1:] = b[:-2] - # Test BufferLength and BufferAssSlice - cb.append('def') # Will not be overwritten - cb[len(cb):] = b[:] - # Test BufferAssItem and BufferMark - cb.append('ghi') # Will be overwritten - cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1])) - # Test BufferRepr - cb.append(repr(cb) + repr(b)) - # Modify foreign buffer - b.append('foo') - b[0]='bar' - b[0:0]=['baz'] - vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number) - # Test assigning to name property - import os - old_name = cb.name - cb.name = 'foo' - cb.append(cb.name[-11:].replace(os.path.sep, '/')) - b.name = 'bar' - cb.append(b.name[-11:].replace(os.path.sep, '/')) - cb.name = old_name - cb.append(cb.name[-17:].replace(os.path.sep, '/')) - del old_name - # Test CheckBuffer - for _b in vim.buffers: - if _b is not cb: - vim.command('bwipeout! ' + str(_b.number)) - del _b - cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid))) - for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")'): - try: - exec(expr) - except vim.error: - pass - else: - # Usually a SEGV here - # Should not happen in any case - cb.append('No exception for ' + expr) - vim.command('cd .') - del b -EOF -:" -:" Test vim.buffers object -:set hidden -:edit a -:buffer # -:edit b -:buffer # -:edit c -:buffer # -py3 << trim EOF - # Check GCing iterator that was not fully exhausted - i = iter(vim.buffers) - cb.append('i:' + str(next(i))) - # and also check creating more than one iterator at a time - i2 = iter(vim.buffers) - cb.append('i2:' + str(next(i2))) - cb.append('i:' + str(next(i))) - # The following should trigger GC and not cause any problems - del i - del i2 - i3 = iter(vim.buffers) - cb.append('i3:' + str(next(i3))) - del i3 - - prevnum = 0 - for b in vim.buffers: - # Check buffer order - if prevnum >= b.number: - cb.append('!!! Buffer numbers not in strictly ascending order') - # Check indexing: vim.buffers[number].number == number - cb.append(str(b.number) + ':' + repr(vim.buffers[b.number]) + '=' + repr(b)) - prevnum = b.number - del prevnum - - cb.append(str(len(vim.buffers))) - - bnums = list(map(lambda b: b.number, vim.buffers))[1:] - - # Test wiping out buffer with existing iterator - i4 = iter(vim.buffers) - cb.append('i4:' + str(next(i4))) - vim.command('bwipeout! ' + str(bnums.pop(0))) - try: - next(i4) - except vim.error: - pass - else: - cb.append('!!!! No vim.error') - i4 = iter(vim.buffers) - vim.command('bwipeout! ' + str(bnums.pop(-1))) - vim.command('bwipeout! ' + str(bnums.pop(-1))) - cb.append('i4:' + str(next(i4))) - try: - next(i4) - except StopIteration: - cb.append('StopIteration') - del i4 - del bnums -EOF -:" -:" Test vim.{tabpage,window}list and vim.{tabpage,window} objects -:tabnew 0 -:tabnew 1 -:vnew a.1 -:tabnew 2 -:vnew a.2 -:vnew b.2 -:vnew c.2 -py3 << trim EOF - cb.append('Number of tabs: ' + str(len(vim.tabpages))) - cb.append('Current tab pages:') - - def W(w): - if '(unknown)' in repr(w): - return '' - else: - return repr(w) - - def Cursor(w, start=len(cb)): - if w.buffer is cb: - return repr((start - w.cursor[0], w.cursor[1])) - else: - return repr(w.cursor) - - for t in vim.tabpages: - cb.append(' ' + repr(t) + '(' + str(t.number) + ')' + ': ' + str(len(t.windows)) + ' windows, current is ' + W(t.window)) - cb.append(' Windows:') - for w in t.windows: - cb.append(' ' + W(w) + '(' + str(w.number) + ')' + ': displays buffer ' + repr(w.buffer) + '; cursor is at ' + Cursor(w)) - # Other values depend on the size of the terminal, so they are checked partly: - for attr in ('height', 'row', 'width', 'col'): - try: - aval = getattr(w, attr) - if type(aval) is not int: - raise TypeError - if aval < 0: - raise ValueError - except Exception as e: - cb.append('!!!!!! Error while getting attribute ' + attr + ': ' + e.__class__.__name__) - del aval - del attr - w.cursor = (len(w.buffer), 0) - del W - del Cursor - cb.append('Number of windows in current tab page: ' + str(len(vim.windows))) - if list(vim.windows) != list(vim.current.tabpage.windows): - cb.append('!!!!!! Windows differ') -EOF -:" -:" Test vim.current -py3 << trim EOF - def H(o): - return repr(o) - cb.append('Current tab page: ' + repr(vim.current.tabpage)) - cb.append('Current window: ' + repr(vim.current.window) + ': ' + H(vim.current.window) + ' is ' + H(vim.current.tabpage.window)) - cb.append('Current buffer: ' + repr(vim.current.buffer) + ': ' + H(vim.current.buffer) + ' is ' + H(vim.current.window.buffer)+ ' is ' + H(vim.current.tabpage.window.buffer)) - del H - # Assigning: fails - try: - vim.current.window = vim.tabpages[0].window - except ValueError: - cb.append('ValueError at assigning foreign tab window') - - for attr in ('window', 'tabpage', 'buffer'): - try: - setattr(vim.current, attr, None) - except TypeError: - cb.append('Type error at assigning None to vim.current.' + attr) - del attr - - # Assigning: success - vim.current.tabpage = vim.tabpages[-2] - vim.current.buffer = cb - vim.current.window = vim.windows[0] - vim.current.window.cursor = (len(vim.current.buffer), 0) - cb.append('Current tab page: ' + repr(vim.current.tabpage)) - cb.append('Current window: ' + repr(vim.current.window)) - cb.append('Current buffer: ' + repr(vim.current.buffer)) - cb.append('Current line: ' + repr(vim.current.line)) - ws = list(vim.windows) - ts = list(vim.tabpages) - for b in vim.buffers: - if b is not cb: - vim.command('bwipeout! ' + str(b.number)) - del b - cb.append('w.valid: ' + repr([w.valid for w in ws])) - cb.append('t.valid: ' + repr([t.valid for t in ts])) - del w - del t - del ts - del ws -EOF -:tabonly! -:only! -:" -:" Test types -py3 << trim EOF - for expr, attr in ( - ('vim.vars', 'Dictionary'), - ('vim.options', 'Options'), - ('vim.bindeval("{}")', 'Dictionary'), - ('vim.bindeval("[]")', 'List'), - ('vim.bindeval("function(\'tr\')")', 'Function'), - ('vim.current.buffer', 'Buffer'), - ('vim.current.range', 'Range'), - ('vim.current.window', 'Window'), - ('vim.current.tabpage', 'TabPage'), - ): - cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr))) - del expr - del attr -EOF -:" -:" Test __dir__() method -py3 << trim EOF - for name, o in ( - ('current', vim.current), - ('buffer', vim.current.buffer), - ('window', vim.current.window), - ('tabpage', vim.current.tabpage), - ('range', vim.current.range), - ('dictionary', vim.bindeval('{}')), - ('list', vim.bindeval('[]')), - ('function', vim.bindeval('function("tr")')), - ('output', sys.stdout), - ): - cb.append(name + ':' + ','.join(dir(o))) - del name - del o -EOF -:" -:" Test vim.*.__new__ -:$put =string(py3eval('vim.Dictionary({})')) -:$put =string(py3eval('vim.Dictionary(a=1)')) -:$put =string(py3eval('vim.Dictionary(((''a'', 1),))')) -:$put =string(py3eval('vim.List()')) -:$put =string(py3eval('vim.List(iter(''abc7''))')) -:$put =string(py3eval('vim.Function(''tr'')')) -:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4])')) -:$put =string(py3eval('vim.Function(''tr'', args=[])')) -:$put =string(py3eval('vim.Function(''tr'', self={})')) -:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4], self={})')) -:$put ='auto_rebind' -:$put =string(py3eval('vim.Function(''tr'', auto_rebind=False)')) -:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4], auto_rebind=False)')) -:$put =string(py3eval('vim.Function(''tr'', args=[], auto_rebind=False)')) -:$put =string(py3eval('vim.Function(''tr'', self={}, auto_rebind=False)')) -:$put =string(py3eval('vim.Function(''tr'', args=[123, 3, 4], self={}, auto_rebind=False)')) -:" -:" Test vim.Function -:function Args(...) -: return a:000 -:endfunction -:function SelfArgs(...) dict -: return [a:000, self] -:endfunction -:" The following four lines should not crash -:let Pt = function('tr', [[]], {'l': []}) -:py3 Pt = vim.bindeval('Pt') -:unlet Pt -:py3 del Pt -py3 << trim EOF - def ecall(out_prefix, func, *args, **kwargs): - line = out_prefix + ': ' - try: - ret = func(*args, **kwargs) - except Exception: - line += '!exception: ' + emsg(sys.exc_info()) - else: - line += '!result: ' + str(vim.Function('string')(ret), 'utf-8') - cb.append(line) - a = vim.Function('Args') - pa1 = vim.Function('Args', args=['abcArgsPA1']) - pa2 = vim.Function('Args', args=[]) - pa3 = vim.Function('Args', args=['abcArgsPA3'], self={'abcSelfPA3': 'abcSelfPA3Val'}) - pa4 = vim.Function('Args', self={'abcSelfPA4': 'abcSelfPA4Val'}) - cb.append('a: ' + repr(a)) - cb.append('pa1: ' + repr(pa1)) - cb.append('pa2: ' + repr(pa2)) - cb.append('pa3: ' + repr(pa3)) - cb.append('pa4: ' + repr(pa4)) - sa = vim.Function('SelfArgs') - psa1 = vim.Function('SelfArgs', args=['abcArgsPSA1']) - psa2 = vim.Function('SelfArgs', args=[]) - psa3 = vim.Function('SelfArgs', args=['abcArgsPSA3'], self={'abcSelfPSA3': 'abcSelfPSA3Val'}) - psa4 = vim.Function('SelfArgs', self={'abcSelfPSA4': 'abcSelfPSA4Val'}) - psa5 = vim.Function('SelfArgs', self={'abcSelfPSA5': 'abcSelfPSA5Val'}, auto_rebind=0) - psa6 = vim.Function('SelfArgs', args=['abcArgsPSA6'], self={'abcSelfPSA6': 'abcSelfPSA6Val'}, auto_rebind=()) - psa7 = vim.Function('SelfArgs', args=['abcArgsPSA7'], auto_rebind=[]) - psa8 = vim.Function('SelfArgs', auto_rebind=False) - psa9 = vim.Function('SelfArgs', self={'abcSelfPSA9': 'abcSelfPSA9Val'}, auto_rebind=True) - psaA = vim.Function('SelfArgs', args=['abcArgsPSAA'], self={'abcSelfPSAA': 'abcSelfPSAAVal'}, auto_rebind=1) - psaB = vim.Function('SelfArgs', args=['abcArgsPSAB'], auto_rebind={'abcARPSAB': 'abcARPSABVal'}) - psaC = vim.Function('SelfArgs', auto_rebind=['abcARPSAC']) - cb.append('sa: ' + repr(sa)) - cb.append('psa1: ' + repr(psa1)) - cb.append('psa2: ' + repr(psa2)) - cb.append('psa3: ' + repr(psa3)) - cb.append('psa4: ' + repr(psa4)) - cb.append('psa5: ' + repr(psa5)) - cb.append('psa6: ' + repr(psa6)) - cb.append('psa7: ' + repr(psa7)) - cb.append('psa8: ' + repr(psa8)) - cb.append('psa9: ' + repr(psa9)) - cb.append('psaA: ' + repr(psaA)) - cb.append('psaB: ' + repr(psaB)) - cb.append('psaC: ' + repr(psaC)) - - psar = vim.Function('SelfArgs', args=[{'abcArgsPSAr': 'abcArgsPSArVal'}], self={'abcSelfPSAr': 'abcSelfPSArVal'}) - psar.args[0]['abcArgsPSAr2'] = [psar.self, psar.args[0]] - psar.self['rec'] = psar - psar.self['self'] = psar.self - psar.self['args'] = psar.args - - try: - cb.append('psar: ' + repr(psar)) - except Exception: - cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) -EOF -:$put ='s(a): '.string(py3eval('a')) -:$put ='s(pa1): '.string(py3eval('pa1')) -:$put ='s(pa2): '.string(py3eval('pa2')) -:$put ='s(pa3): '.string(py3eval('pa3')) -:$put ='s(pa4): '.string(py3eval('pa4')) -:$put ='s(sa): '.string(py3eval('sa')) -:$put ='s(psa1): '.string(py3eval('psa1')) -:$put ='s(psa2): '.string(py3eval('psa2')) -:$put ='s(psa3): '.string(py3eval('psa3')) -:$put ='s(psa4): '.string(py3eval('psa4')) -:$put ='s(psa5): '.string(py3eval('psa5')) -:$put ='s(psa6): '.string(py3eval('psa6')) -:$put ='s(psa7): '.string(py3eval('psa7')) -:$put ='s(psa8): '.string(py3eval('psa8')) -:$put ='s(psa9): '.string(py3eval('psa9')) -:$put ='s(psaA): '.string(py3eval('psaA')) -:$put ='s(psaB): '.string(py3eval('psaB')) -:$put ='s(psaC): '.string(py3eval('psaC')) -: -:for v in ['sa', 'psa1', 'psa2', 'psa3', 'psa4', 'psa5', 'psa6', 'psa7', 'psa8', 'psa9', 'psaA', 'psaB', 'psaC'] -: let d = {'f': py3eval(v)} -: $put ='d.'.v.'(): '.string(d.f()) -:endfor -: -:py3 ecall('a()', a, ) -:py3 ecall('pa1()', pa1, ) -:py3 ecall('pa2()', pa2, ) -:py3 ecall('pa3()', pa3, ) -:py3 ecall('pa4()', pa4, ) -:py3 ecall('sa()', sa, ) -:py3 ecall('psa1()', psa1, ) -:py3 ecall('psa2()', psa2, ) -:py3 ecall('psa3()', psa3, ) -:py3 ecall('psa4()', psa4, ) -: -:py3 ecall('a(42, 43)', a, 42, 43) -:py3 ecall('pa1(42, 43)', pa1, 42, 43) -:py3 ecall('pa2(42, 43)', pa2, 42, 43) -:py3 ecall('pa3(42, 43)', pa3, 42, 43) -:py3 ecall('pa4(42, 43)', pa4, 42, 43) -:py3 ecall('sa(42, 43)', sa, 42, 43) -:py3 ecall('psa1(42, 43)', psa1, 42, 43) -:py3 ecall('psa2(42, 43)', psa2, 42, 43) -:py3 ecall('psa3(42, 43)', psa3, 42, 43) -:py3 ecall('psa4(42, 43)', psa4, 42, 43) -: -:py3 ecall('a(42, self={"20": 1})', a, 42, self={'20': 1}) -:py3 ecall('pa1(42, self={"20": 1})', pa1, 42, self={'20': 1}) -:py3 ecall('pa2(42, self={"20": 1})', pa2, 42, self={'20': 1}) -:py3 ecall('pa3(42, self={"20": 1})', pa3, 42, self={'20': 1}) -:py3 ecall('pa4(42, self={"20": 1})', pa4, 42, self={'20': 1}) -:py3 ecall('sa(42, self={"20": 1})', sa, 42, self={'20': 1}) -:py3 ecall('psa1(42, self={"20": 1})', psa1, 42, self={'20': 1}) -:py3 ecall('psa2(42, self={"20": 1})', psa2, 42, self={'20': 1}) -:py3 ecall('psa3(42, self={"20": 1})', psa3, 42, self={'20': 1}) -:py3 ecall('psa4(42, self={"20": 1})', psa4, 42, self={'20': 1}) -: -:py3 ecall('a(self={"20": 1})', a, self={'20': 1}) -:py3 ecall('pa1(self={"20": 1})', pa1, self={'20': 1}) -:py3 ecall('pa2(self={"20": 1})', pa2, self={'20': 1}) -:py3 ecall('pa3(self={"20": 1})', pa3, self={'20': 1}) -:py3 ecall('pa4(self={"20": 1})', pa4, self={'20': 1}) -:py3 ecall('sa(self={"20": 1})', sa, self={'20': 1}) -:py3 ecall('psa1(self={"20": 1})', psa1, self={'20': 1}) -:py3 ecall('psa2(self={"20": 1})', psa2, self={'20': 1}) -:py3 ecall('psa3(self={"20": 1})', psa3, self={'20': 1}) -:py3 ecall('psa4(self={"20": 1})', psa4, self={'20': 1}) -py3 << trim EOF - def s(v): - if v is None: - return repr(v) - else: - return str(vim.Function('string')(v), 'utf-8') - - cb.append('a.args: ' + s(a.args)) - cb.append('pa1.args: ' + s(pa1.args)) - cb.append('pa2.args: ' + s(pa2.args)) - cb.append('pa3.args: ' + s(pa3.args)) - cb.append('pa4.args: ' + s(pa4.args)) - cb.append('sa.args: ' + s(sa.args)) - cb.append('psa1.args: ' + s(psa1.args)) - cb.append('psa2.args: ' + s(psa2.args)) - cb.append('psa3.args: ' + s(psa3.args)) - cb.append('psa4.args: ' + s(psa4.args)) - - cb.append('a.self: ' + s(a.self)) - cb.append('pa1.self: ' + s(pa1.self)) - cb.append('pa2.self: ' + s(pa2.self)) - cb.append('pa3.self: ' + s(pa3.self)) - cb.append('pa4.self: ' + s(pa4.self)) - cb.append('sa.self: ' + s(sa.self)) - cb.append('psa1.self: ' + s(psa1.self)) - cb.append('psa2.self: ' + s(psa2.self)) - cb.append('psa3.self: ' + s(psa3.self)) - cb.append('psa4.self: ' + s(psa4.self)) - - cb.append('a.name: ' + s(a.name)) - cb.append('pa1.name: ' + s(pa1.name)) - cb.append('pa2.name: ' + s(pa2.name)) - cb.append('pa3.name: ' + s(pa3.name)) - cb.append('pa4.name: ' + s(pa4.name)) - cb.append('sa.name: ' + s(sa.name)) - cb.append('psa1.name: ' + s(psa1.name)) - cb.append('psa2.name: ' + s(psa2.name)) - cb.append('psa3.name: ' + s(psa3.name)) - cb.append('psa4.name: ' + s(psa4.name)) - - cb.append('a.auto_rebind: ' + s(a.auto_rebind)) - cb.append('pa1.auto_rebind: ' + s(pa1.auto_rebind)) - cb.append('pa2.auto_rebind: ' + s(pa2.auto_rebind)) - cb.append('pa3.auto_rebind: ' + s(pa3.auto_rebind)) - cb.append('pa4.auto_rebind: ' + s(pa4.auto_rebind)) - cb.append('sa.auto_rebind: ' + s(sa.auto_rebind)) - cb.append('psa1.auto_rebind: ' + s(psa1.auto_rebind)) - cb.append('psa2.auto_rebind: ' + s(psa2.auto_rebind)) - cb.append('psa3.auto_rebind: ' + s(psa3.auto_rebind)) - cb.append('psa4.auto_rebind: ' + s(psa4.auto_rebind)) - cb.append('psa5.auto_rebind: ' + s(psa5.auto_rebind)) - cb.append('psa6.auto_rebind: ' + s(psa6.auto_rebind)) - cb.append('psa7.auto_rebind: ' + s(psa7.auto_rebind)) - cb.append('psa8.auto_rebind: ' + s(psa8.auto_rebind)) - cb.append('psa9.auto_rebind: ' + s(psa9.auto_rebind)) - cb.append('psaA.auto_rebind: ' + s(psaA.auto_rebind)) - cb.append('psaB.auto_rebind: ' + s(psaB.auto_rebind)) - cb.append('psaC.auto_rebind: ' + s(psaC.auto_rebind)) - - del s - - del a - del pa1 - del pa2 - del pa3 - del pa4 - del sa - del psa1 - del psa2 - del psa3 - del psa4 - del psa5 - del psa6 - del psa7 - del psa8 - del psa9 - del psaA - del psaB - del psaC - del psar - - del ecall -EOF -:" -:" Test stdout/stderr -:redir => messages -:py3 sys.stdout.write('abc8') ; sys.stdout.write('def') -:py3 sys.stderr.write('abc9') ; sys.stderr.write('def') -:py3 sys.stdout.writelines(iter('abcA')) -:py3 sys.stderr.writelines(iter('abcB')) -:redir END -:$put =string(substitute(messages, '\d\+', '', 'g')) -:" Test subclassing -:fun Put(...) -: $put =string(a:000) -: return a:000 -:endfun -py3 << trim EOF - class DupDict(vim.Dictionary): - def __setitem__(self, key, value): - super(DupDict, self).__setitem__(key, value) - super(DupDict, self).__setitem__('dup_' + key, value) - dd = DupDict() - dd['a'] = 'b' - - class DupList(vim.List): - def __getitem__(self, idx): - return [super(DupList, self).__getitem__(idx)] * 2 - - dl = DupList() - dl2 = DupList(iter('abcC')) - dl.extend(dl2[0]) - - class DupFun(vim.Function): - def __call__(self, arg): - return super(DupFun, self).__call__(arg, arg) - - df = DupFun('Put') -EOF -:$put =string(sort(keys(py3eval('dd')))) -:$put =string(py3eval('dl')) -:$put =string(py3eval('dl2')) -:$put =string(py3eval('df(2)')) -:$put =string(py3eval('dl') is# py3eval('dl')) -:$put =string(py3eval('dd') is# py3eval('dd')) -:$put =string(py3eval('df')) -:delfunction Put -py3 << trim EOF - del DupDict - del DupList - del DupFun - del dd - del dl - del dl2 - del df -EOF -:" -:" Test chdir -py3 << trim EOF - import os - fnamemodify = vim.Function('fnamemodify') - cb.append(str(fnamemodify('.', ':p:h:t'))) - cb.append(vim.eval('@%')) - os.chdir('..') - path = fnamemodify('.', ':p:h:t') - if path != b'src': - # Running tests from a shadow directory, so move up another level - # This will result in @% looking like shadow/testdir/test87.in, hence the - # slicing to remove the leading path and path separator - os.chdir('..') - cb.append(str(fnamemodify('.', ':p:h:t'))) - cb.append(vim.eval('@%')[len(path)+1:].replace(os.path.sep, '/')) - os.chdir(path) - else: - cb.append(str(fnamemodify('.', ':p:h:t'))) - cb.append(vim.eval('@%').replace(os.path.sep, '/')) - del path - os.chdir('testdir') - cb.append(str(fnamemodify('.', ':p:h:t'))) - cb.append(vim.eval('@%')) - del fnamemodify -EOF -:" -:" Test errors -:fun F() dict -:endfun -:fun D() -:endfun -py3 << trim EOF - d = vim.Dictionary() - ned = vim.Dictionary(foo='bar', baz='abcD') - dl = vim.Dictionary(a=1) - dl.locked = True - l = vim.List() - ll = vim.List('abcE') - ll.locked = True - nel = vim.List('abcO') - f = vim.Function('string') - fd = vim.Function('F') - fdel = vim.Function('D') - vim.command('delfunction D') - - def subexpr_test(expr, name, subexprs): - cb.append('>>> Testing %s using %s' % (name, expr)) - for subexpr in subexprs: - ee(expr % subexpr) - cb.append('<<< Finished') - - def stringtochars_test(expr): - return subexpr_test(expr, 'StringToChars', ( - '1', # Fail type checks - 'b"\\0"', # Fail PyString_AsStringAndSize(object, , NULL) check - '"\\0"', # Fail PyString_AsStringAndSize(bytes, , NULL) check - )) - - class Mapping(object): - def __init__(self, d): - self.d = d - - def __getitem__(self, key): - return self.d[key] - - def keys(self): - return self.d.keys() - - def items(self): - return self.d.items() - - def convertfrompyobject_test(expr, recurse=True): - # pydict_to_tv - stringtochars_test(expr % '{%s : 1}') - if recurse: - convertfrompyobject_test(expr % '{"abcF" : %s}', False) - # pymap_to_tv - stringtochars_test(expr % 'Mapping({%s : 1})') - if recurse: - convertfrompyobject_test(expr % 'Mapping({"abcG" : %s})', False) - # pyseq_to_tv - iter_test(expr) - return subexpr_test(expr, 'ConvertFromPyObject', ( - 'None', # Not conversible - '{b"": 1}', # Empty key not allowed - '{"": 1}', # Same, but with unicode object - 'FailingMapping()', # - 'FailingMappingKey()', # - 'FailingNumber()', # - )) - - def convertfrompymapping_test(expr): - convertfrompyobject_test(expr) - return subexpr_test(expr, 'ConvertFromPyMapping', ( - '[]', - )) - - def iter_test(expr): - return subexpr_test(expr, '*Iter*', ( - 'FailingIter()', - 'FailingIterNext()', - )) - - def number_test(expr, natural=False, unsigned=False): - if natural: - unsigned = True - return subexpr_test(expr, 'NumberToLong', ( - '[]', - 'None', - ) + (('-1',) if unsigned else ()) - + (('0',) if natural else ())) - - class FailingTrue(object): - def __bool__(self): - raise NotImplementedError('bool') - - class FailingIter(object): - def __iter__(self): - raise NotImplementedError('iter') - - class FailingIterNext(object): - def __iter__(self): - return self - - def __next__(self): - raise NotImplementedError('next') - - class FailingIterNextN(object): - def __init__(self, n): - self.n = n - - def __iter__(self): - return self - - def __next__(self): - if self.n: - self.n -= 1 - return 1 - else: - raise NotImplementedError('next N') - - class FailingMappingKey(object): - def __getitem__(self, item): - raise NotImplementedError('getitem:mappingkey') - - def keys(self): - return list("abcH") - - class FailingMapping(object): - def __getitem__(self): - raise NotImplementedError('getitem:mapping') - - def keys(self): - raise NotImplementedError('keys') - - class FailingList(list): - def __getitem__(self, idx): - if i == 2: - raise NotImplementedError('getitem:list') - else: - return super(FailingList, self).__getitem__(idx) - - class NoArgsCall(object): - def __call__(self): - pass - - class FailingCall(object): - def __call__(self, path): - raise NotImplementedError('call') - - class FailingNumber(object): - def __int__(self): - raise NotImplementedError('int') - - cb.append("> Output") - cb.append(">> OutputSetattr") - ee('del sys.stdout.softspace') - number_test('sys.stdout.softspace = %s', unsigned=True) - number_test('sys.stderr.softspace = %s', unsigned=True) - ee('assert sys.stdout.isatty()==False') - ee('assert sys.stdout.seekable()==False') - ee('sys.stdout.close()') - ee('sys.stdout.flush()') - ee('assert sys.stderr.isatty()==False') - ee('assert sys.stderr.seekable()==False') - ee('sys.stderr.close()') - ee('sys.stderr.flush()') - ee('sys.stdout.attr = None') - cb.append(">> OutputWrite") - ee('assert sys.stdout.writable()==True') - ee('assert sys.stdout.readable()==False') - ee('assert sys.stderr.writable()==True') - ee('assert sys.stderr.readable()==False') - ee('assert sys.stdout.closed()==False') - ee('assert sys.stderr.closed()==False') - ee('assert sys.stdout.errors=="strict"') - ee('assert sys.stderr.errors=="strict"') - ee('assert sys.stdout.encoding==sys.stderr.encoding') - ee('sys.stdout.write(None)') - cb.append(">> OutputWriteLines") - ee('sys.stdout.writelines(None)') - ee('sys.stdout.writelines([1])') - iter_test('sys.stdout.writelines(%s)') - cb.append("> VimCommand") - stringtochars_test('vim.command(%s)') - ee('vim.command("", 2)') - #! Not checked: vim->python exceptions translating: checked later - cb.append("> VimToPython") - #! Not checked: everything: needs errors in internal python functions - cb.append("> VimEval") - stringtochars_test('vim.eval(%s)') - ee('vim.eval("", FailingTrue())') - #! Not checked: everything: needs errors in internal python functions - cb.append("> VimEvalPy") - stringtochars_test('vim.bindeval(%s)') - ee('vim.eval("", 2)') - #! Not checked: vim->python exceptions translating: checked later - cb.append("> VimStrwidth") - stringtochars_test('vim.strwidth(%s)') - cb.append("> VimForeachRTP") - ee('vim.foreach_rtp(None)') - ee('vim.foreach_rtp(NoArgsCall())') - ee('vim.foreach_rtp(FailingCall())') - ee('vim.foreach_rtp(int, 2)') - cb.append('> import') - old_rtp = vim.options['rtp'] - vim.options['rtp'] = os.getcwd().replace('\\', '\\\\').replace(',', '\\,') - ee('import xxx_no_such_module_xxx') - ee('import failing_import') - ee('import failing') - vim.options['rtp'] = old_rtp - del old_rtp - cb.append("> Options") - cb.append(">> OptionsItem") - ee('vim.options["abcQ"]') - ee('vim.options[""]') - stringtochars_test('vim.options[%s]') - cb.append(">> OptionsContains") - stringtochars_test('%s in vim.options') - cb.append("> Dictionary") - cb.append(">> DictionaryConstructor") - ee('vim.Dictionary("abcI")') - ##! Not checked: py_dict_alloc failure - cb.append(">> DictionarySetattr") - ee('del d.locked') - ee('d.locked = FailingTrue()') - ee('vim.vvars.locked = False') - ee('d.scope = True') - ee('d.xxx = True') - cb.append(">> _DictionaryItem") - ee('d.get("a", 2, 3)') - stringtochars_test('d.get(%s)') - ee('d.pop("a")') - ee('dl.pop("a")') - cb.append(">> DictionaryContains") - ee('"" in d') - ee('0 in d') - cb.append(">> DictionaryIterNext") - ee('for i in ned: ned["a"] = 1') - del i - cb.append(">> DictionaryAssItem") - ee('dl["b"] = 1') - stringtochars_test('d[%s] = 1') - convertfrompyobject_test('d["a"] = %s') - cb.append(">> DictionaryUpdate") - cb.append(">>> kwargs") - cb.append(">>> iter") - ee('d.update(FailingMapping())') - ee('d.update([FailingIterNext()])') - ee('d.update([FailingIterNextN(1)])') - iter_test('d.update(%s)') - convertfrompyobject_test('d.update(%s)') - stringtochars_test('d.update(((%s, 0),))') - convertfrompyobject_test('d.update((("a", %s),))') - cb.append(">> DictionaryPopItem") - ee('d.popitem(1, 2)') - cb.append(">> DictionaryHasKey") - ee('d.has_key()') - cb.append("> List") - cb.append(">> ListConstructor") - ee('vim.List(1, 2)') - ee('vim.List(a=1)') - iter_test('vim.List(%s)') - convertfrompyobject_test('vim.List([%s])') - cb.append(">> ListItem") - ee('l[1000]') - cb.append(">> ListAssItem") - ee('ll[1] = 2') - ee('l[1000] = 3') - cb.append(">> ListAssSlice") - ee('ll[1:100] = "abcJ"') - iter_test('l[:] = %s') - ee('nel[1:10:2] = "abcK"') - cb.append(repr(tuple(nel))) - ee('nel[1:10:2] = "a"') - cb.append(repr(tuple(nel))) - ee('nel[1:1:-1] = "a"') - cb.append(repr(tuple(nel))) - ee('nel[:] = FailingIterNextN(2)') - cb.append(repr(tuple(nel))) - convertfrompyobject_test('l[:] = [%s]') - cb.append(">> ListConcatInPlace") - iter_test('l.extend(%s)') - convertfrompyobject_test('l.extend([%s])') - cb.append(">> ListSetattr") - ee('del l.locked') - ee('l.locked = FailingTrue()') - ee('l.xxx = True') - cb.append("> Function") - cb.append(">> FunctionConstructor") - cb.append(">>> FunctionConstructor") - ee('vim.Function("123")') - ee('vim.Function("xxx_non_existent_function_xxx")') - ee('vim.Function("xxx#non#existent#function#xxx")') - ee('vim.Function("xxx_non_existent_function_xxx2", args=[])') - ee('vim.Function("xxx_non_existent_function_xxx3", self={})') - ee('vim.Function("xxx_non_existent_function_xxx4", args=[], self={})') - cb.append(">>> FunctionNew") - ee('vim.Function("tr", self="abcFuncSelf")') - ee('vim.Function("tr", args=427423)') - ee('vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2")') - ee('vim.Function(self="abcFuncSelf2", args="abcFuncArgs2")') - ee('vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2")') - ee('vim.Function("tr", "")') - cb.append(">> FunctionCall") - convertfrompyobject_test('f(%s)') - convertfrompymapping_test('fd(self=%s)') - cb.append("> TabPage") - cb.append(">> TabPageAttr") - ee('vim.current.tabpage.xxx') - cb.append("> TabList") - cb.append(">> TabListItem") - ee('vim.tabpages[1000]') - cb.append("> Window") - cb.append(">> WindowAttr") - ee('vim.current.window.xxx') - cb.append(">> WindowSetattr") - ee('vim.current.window.buffer = 0') - ee('vim.current.window.cursor = (100000000, 100000000)') - ee('vim.current.window.cursor = True') - number_test('vim.current.window.height = %s', unsigned=True) - number_test('vim.current.window.width = %s', unsigned=True) - ee('vim.current.window.xxxxxx = True') - cb.append("> WinList") - cb.append(">> WinListItem") - ee('vim.windows[1000]') - cb.append("> Buffer") - cb.append(">> StringToLine (indirect)") - ee('vim.current.buffer[0] = "\\na"') - ee('vim.current.buffer[0] = b"\\na"') - cb.append(">> SetBufferLine (indirect)") - ee('vim.current.buffer[0] = True') - cb.append(">> SetBufferLineList (indirect)") - ee('vim.current.buffer[:] = True') - ee('vim.current.buffer[:] = ["\\na", "bc"]') - cb.append(">> InsertBufferLines (indirect)") - ee('vim.current.buffer.append(None)') - ee('vim.current.buffer.append(["\\na", "bc"])') - ee('vim.current.buffer.append("\\nbc")') - cb.append(">> RBItem") - ee('vim.current.buffer[100000000]') - cb.append(">> RBAsItem") - ee('vim.current.buffer[100000000] = ""') - cb.append(">> BufferAttr") - ee('vim.current.buffer.xxx') - cb.append(">> BufferSetattr") - ee('vim.current.buffer.name = True') - ee('vim.current.buffer.xxx = True') - cb.append(">> BufferMark") - ee('vim.current.buffer.mark(0)') - ee('vim.current.buffer.mark("abcM")') - ee('vim.current.buffer.mark("!")') - cb.append(">> BufferRange") - ee('vim.current.buffer.range(1, 2, 3)') - cb.append("> BufMap") - cb.append(">> BufMapItem") - ee('vim.buffers[100000000]') - number_test('vim.buffers[%s]', natural=True) - cb.append("> Current") - cb.append(">> CurrentGetattr") - ee('vim.current.xxx') - cb.append(">> CurrentSetattr") - ee('vim.current.line = True') - ee('vim.current.buffer = True') - ee('vim.current.window = True') - ee('vim.current.tabpage = True') - ee('vim.current.xxx = True') - del d - del ned - del dl - del l - del ll - del nel - del f - del fd - del fdel - del subexpr_test - del stringtochars_test - del Mapping - del convertfrompyobject_test - del convertfrompymapping_test - del iter_test - del number_test - del FailingTrue - del FailingIter - del FailingIterNext - del FailingIterNextN - del FailingMapping - del FailingMappingKey - del FailingList - del NoArgsCall - del FailingCall - del FailingNumber -EOF -:delfunction F -:" -:" Test import -py3 << trim EOF - sys.path.insert(0, os.path.join(os.getcwd(), 'python_before')) - sys.path.append(os.path.join(os.getcwd(), 'python_after')) - vim.options['rtp'] = os.getcwd().replace(',', '\\,').replace('\\', '\\\\') - l = [] - def callback(path): - l.append(os.path.relpath(path)) - vim.foreach_rtp(callback) - cb.append(repr(l)) - del l - def callback(path): - return os.path.relpath(path) - cb.append(repr(vim.foreach_rtp(callback))) - del callback - from module import dir as d - from modulex import ddir - cb.append(d + ',' + ddir) - import before - cb.append(before.dir) - import after - cb.append(after.dir) - import topmodule as tm - import topmodule.submodule as tms - import topmodule.submodule.subsubmodule.subsubsubmodule as tmsss - cb.append(tm.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/__init__.py'):]) - cb.append(tms.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/__init__.py'):]) - cb.append(tmsss.__file__.replace(os.path.sep, '/')[-len('modulex/topmodule/submodule/subsubmodule/subsubsubmodule.py'):]) - del before - del after - del d - del ddir - del tm - del tms - del tmsss -EOF -:" -:" Test exceptions -:fun Exe(e) -: execute a:e -:endfun -py3 << trim EOF - Exe = vim.bindeval('function("Exe")') - ee('vim.command("throw \'abcN\'")') - ee('Exe("throw \'def\'")') - ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")') - ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")') - ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")') - ee('vim.eval("xxx_unknown_function_xxx()")') - ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")') - del Exe -EOF -:delfunction Exe -:" -:" Regression: interrupting vim.command propagates to next vim.command -py3 << trim EOF - def test_keyboard_interrupt(): - try: - vim.command('while 1 | endwhile') - except KeyboardInterrupt: - cb.append('Caught KeyboardInterrupt') - except Exception: - cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) - else: - cb.append('!!!!!!!! No exception') - try: - vim.command('$ put =\'Running :put\'') - except KeyboardInterrupt: - cb.append('!!!!!!!! Caught KeyboardInterrupt') - except Exception: - cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) - else: - cb.append('No exception') -EOF -:debuggreedy -:call inputsave() -:call feedkeys("s\ns\ns\ns\nq\n") -:redir => output -:debug silent! py3 test_keyboard_interrupt() -:redir END -:0 debuggreedy -:call inputrestore() -:silent $put =output -:unlet output -:py3 del test_keyboard_interrupt -:" -:" Cleanup -py3 << trim EOF - del cb - del ee - del emsg - del sys - del os - del vim -EOF -:endfun -:" -:fun RunTest() -:let checkrefs = !empty($PYTHONDUMPREFS) -:let start = getline(1, '$') -:for i in range(checkrefs ? 10 : 1) -: if i != 0 -: %d _ -: call setline(1, start) -: endif -: call Test() -: if i == 0 -: let result = getline(1, '$') -: endif -:endfor -:if checkrefs -: %d _ -: call setline(1, result) -:endif -:endfun -:" -:call RunTest() -:delfunction RunTest -:delfunction Test -:call garbagecollect(1) -:" -:/^start:/,$wq! test.out -:/^start:/,$w! test.out -:" vim: et ts=4 isk-=\: -:while getchar(0) isnot 0|endwhile -ENDTEST - -start: diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok deleted file mode 100644 index c42acdf386..0000000000 --- a/src/testdir/test87.ok +++ /dev/null @@ -1,1445 +0,0 @@ -start: -[1, 'as''d', [1, 2, function('strlen'), {'a': 1}]] -[1, 2, function('strlen'), {'a': 1}] -Vim(put):E684: -[0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] -[0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] -1 -[b'-1', b'0', b'1', b'b', b'f'] -[-1, , , , b'asd'] -[(b'-1', ), (b'0', -1), (b'1', b'asd'), (b'b', ), (b'f', )] -'-1' : {'a': 1} -'0' : -1 -'1' : 'asd' -'b' : [1, 2, function('strlen')] -'f' : function('1') -[0, function('strlen')] -[3] -[1, 2, function('strlen')] -[1, 2, function('strlen')] -1 -'asd' -2 -True -False -True -False -[b'0'] -{'0': -1} -(b'0', -1) -None -[] -[0, 1, 2, 3] -[0, 1, 2, 3] -[0, 1, 3] -[0, 1] -[0, 1] -[0, 1] -[0, 1, 2, 3] -[0, 1, 2, 3] -[0, 2, 3] -[2, 3] -[2, 3] -[2, 3] -[1, 3] -[0, 2] -[0, 1, 2, 3] -['a', 0, 1, 2, 3] -[0, 'b', 2, 3] -[0, 1, 'c'] -[0, 1, 2, 3, 'd'] -[0, 1, 2, 'e', 3] -['f', 2, 3] -[0, 1, 'g', 2, 3] -['h'] -[0, 1, 10, 3, 20, 5, 6, 7] -[0, 1, 2, 3, 20, 5, 10, 7] -[0, 1, 2, 3, 4, 5, 6, 7] -[0, 1, 2, 3, 4, 5, 6, 7] -[0, 1, 2, 3, 4, 5, 6, 7] -l[2] threw vim.error: error:('list is locked',) -[0, 1, 2, 3] -[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd'] -[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}] -[function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New'] -l[1](1, 2, 3):(, error('Vim:E725: Calling dict function without Dictionary: DictNew',)) -f(1, 2, 3):(, error('Vim:E117: Unknown function: New',)) -[0.0, 0.0] -KeyError -TypeError -TypeError -ValueError -TypeError -TypeError -KeyError -KeyError -d : locked:0;scope:0 -dl : locked:1;scope:0 -v: : locked:2;scope:1 -g: : locked:0;scope:2 -d:{'abc2': 1} -dl:{'def': 1} -l : locked:0 -ll : locked:1 -l:[0] -ll:[1] -[0, 1, 2] -['a', 'b'] -['c', 1] -['d', ['e']] -py3eval("None") = v:none -0.0 -"\0": Vim(let):E859: -{"\0": 1}: Vim(let):E859: -undefined_name: Vim(let):NameE -vim: Vim(let):E859: -[1] -[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1] -[0, 1, 2, 3] -[2, 3, 4, 5] -[0, 1] -[4, 5] -[2, 3] -[] -[2, 3] -[] -[0, 1, 2, 3, 4, 5] -[0, 1, 2, 3, 4, 5] -[0, 1, 2, 3, 4, 5] -[4, 3] -[0, 2, 4] -[] -Abc -bac -def -bar -jkl -wopts iters equal: 1 -bopts iters equal: 1 ->>> paste - g/w/b:1/0/0 - g/w/b (in):1/0/0 - p/gopts1: False - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1! KeyError - inv: 2! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 1 - W: 1:1 2:1 3:1 4:1 - B: 1:1 2:1 3:1 4:1 - del wopts3! KeyError - del bopts3! KeyError - G: 1 - W: 1:1 2:1 3:1 4:1 - B: 1:1 2:1 3:1 4:1 ->>> previewheight - g/w/b:1/0/0 - g/w/b (in):1/0/0 - p/gopts1: 12 - inv: 'a'! TypeError - p/wopts1! KeyError - inv: 'a'! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1! KeyError - inv: 'a'! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 5 - W: 1:5 2:5 3:5 4:5 - B: 1:5 2:5 3:5 4:5 - del wopts3! KeyError - del bopts3! KeyError - G: 5 - W: 1:5 2:5 3:5 4:5 - B: 1:5 2:5 3:5 4:5 ->>> operatorfunc - g/w/b:1/0/0 - g/w/b (in):1/0/0 - p/gopts1: b'' - inv: 2! TypeError - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1! KeyError - inv: 2! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 'A' - W: 1:'A' 2:'A' 3:'A' 4:'A' - B: 1:'A' 2:'A' 3:'A' 4:'A' - del wopts3! KeyError - del bopts3! KeyError - G: 'A' - W: 1:'A' 2:'A' 3:'A' 4:'A' - B: 1:'A' 2:'A' 3:'A' 4:'A' ->>> number - g/w/b:0/1/0 - g/w/b (in):0/1/0 - p/gopts1! KeyError - inv: 0! KeyError - gopts1! KeyError - p/wopts1: False - p/bopts1! KeyError - inv: 0! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 0 - W: 1:1 2:1 3:0 4:0 - B: 1:1 2:1 3:0 4:0 - del wopts3! ValueError - del bopts3! KeyError - G: 0 - W: 1:1 2:1 3:0 4:0 - B: 1:1 2:1 3:0 4:0 ->>> numberwidth - g/w/b:0/1/0 - g/w/b (in):0/1/0 - p/gopts1! KeyError - inv: -100! KeyError - gopts1! KeyError - p/wopts1: 8 - inv: -100! error - p/bopts1! KeyError - inv: -100! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: 8 - W: 1:3 2:5 3:2 4:8 - B: 1:3 2:5 3:2 4:8 - del wopts3! ValueError - del bopts3! KeyError - G: 8 - W: 1:3 2:5 3:2 4:8 - B: 1:3 2:5 3:2 4:8 ->>> colorcolumn - g/w/b:0/1/0 - g/w/b (in):0/1/0 - p/gopts1! KeyError - inv: 'abc4'! KeyError - gopts1! KeyError - p/wopts1: b'' - inv: 'abc4'! error - p/bopts1! KeyError - inv: 'abc4'! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: '' - W: 1:'+2' 2:'+3' 3:'+1' 4:'' - B: 1:'+2' 2:'+3' 3:'+1' 4:'' - del wopts3! ValueError - del bopts3! KeyError - G: '' - W: 1:'+2' 2:'+3' 3:'+1' 4:'' - B: 1:'+2' 2:'+3' 3:'+1' 4:'' ->>> statusline - g/w/b:1/1/0 - g/w/b (in):1/1/0 - p/gopts1: b'' - inv: 0! TypeError - p/wopts1: None - inv: 0! TypeError - p/bopts1! KeyError - inv: 0! KeyError - bopts1! KeyError - bopts2! KeyError - bopts3! KeyError - G: '1' - W: 1:'2' 2:'4' 3:'1' 4:'1' - B: 1:'2' 2:'4' 3:'1' 4:'1' - del bopts3! KeyError - G: '1' - W: 1:'2' 2:'1' 3:'1' 4:'1' - B: 1:'2' 2:'1' 3:'1' 4:'1' ->>> autoindent - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 2! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: False - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 - del wopts3! KeyError - del bopts3! ValueError - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 ->>> shiftwidth - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 3! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 3! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: 8 - G: 8 - W: 1:0 2:2 3:8 4:1 - B: 1:0 2:2 3:8 4:1 - del wopts3! KeyError - del bopts3! ValueError - G: 8 - W: 1:0 2:2 3:8 4:1 - B: 1:0 2:2 3:8 4:1 ->>> omnifunc - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 1! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 1! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: b'' - inv: 1! TypeError - G: '' - W: 1:'A' 2:'B' 3:'' 4:'C' - B: 1:'A' 2:'B' 3:'' 4:'C' - del wopts3! KeyError - del bopts3! ValueError - G: '' - W: 1:'A' 2:'B' 3:'' 4:'C' - B: 1:'A' 2:'B' 3:'' 4:'C' ->>> preserveindent - g/w/b:0/0/1 - g/w/b (in):0/0/1 - p/gopts1! KeyError - inv: 2! KeyError - gopts1! KeyError - p/wopts1! KeyError - inv: 2! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: False - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 - del wopts3! KeyError - del bopts3! ValueError - G: 0 - W: 1:0 2:1 3:0 4:1 - B: 1:0 2:1 3:0 4:1 ->>> path - g/w/b:1/0/1 - g/w/b (in):1/0/1 - p/gopts1: b'.,..,,' - inv: 0! TypeError - p/wopts1! KeyError - inv: 0! KeyError - wopts1! KeyError - wopts2! KeyError - wopts3! KeyError - p/bopts1: None - inv: 0! TypeError - G: '.,,' - W: 1:'.,,' 2:',,' 3:'.,,' 4:'.' - B: 1:'.,,' 2:',,' 3:'.,,' 4:'.' - del wopts3! KeyError - G: '.,,' - W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' - B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' -First line -First line -def -First line -Second line -Third line -(7, 2) - -baz -bar -Second line -Third line -foo -1:BufFilePre:1 -1:BufFilePost:1 -testdir/foo -5:BufFilePre:5 -5:BufFilePost:5 -testdir/bar -1:BufFilePre:1 -1:BufFilePost:1 -testdir/test87.in -valid: b:False, cb:True -i: -i2: -i: -i3: -1:= -8:= -9:= -10:= -4 -i4: -i4: -StopIteration -Number of tabs: 4 -Current tab pages: - (1): 1 windows, current is - Windows: - (1): displays buffer ; cursor is at (37, 0) - (2): 1 windows, current is - Windows: - (1): displays buffer ; cursor is at (1, 0) - (3): 2 windows, current is - Windows: - (1): displays buffer ; cursor is at (1, 0) - (2): displays buffer ; cursor is at (1, 0) - (4): 4 windows, current is - Windows: - (1): displays buffer ; cursor is at (1, 0) - (2): displays buffer ; cursor is at (1, 0) - (3): displays buffer ; cursor is at (1, 0) - (4): displays buffer ; cursor is at (1, 0) -Number of windows in current tab page: 4 -Current tab page: -Current window: : is -Current buffer: : is is -ValueError at assigning foreign tab window -Type error at assigning None to vim.current.window -Type error at assigning None to vim.current.tabpage -Type error at assigning None to vim.current.buffer -Current tab page: -Current window: -Current buffer: -Current line: 'Type error at assigning None to vim.current.buffer' -w.valid: [True, False] -t.valid: [True, False, True, False] -vim.vars:Dictionary:True -vim.options:Options:True -vim.bindeval("{}"):Dictionary:True -vim.bindeval("[]"):List:True -vim.bindeval("function('tr')"):Function:True -vim.current.buffer:Buffer:True -vim.current.range:Range:True -vim.current.window:Window:True -vim.current.tabpage:TabPage:True -current:__dir__,buffer,line,range,tabpage,window -buffer:__dir__,append,mark,name,number,options,range,valid,vars -window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars,width -tabpage:__dir__,number,valid,vars,window,windows -range:__dir__,append,end,start -dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values -list:__dir__,extend,locked -function:__dir__,args,auto_rebind,self,softspace -output:__dir__,close,closed,flush,isatty,readable,seekable,softspace,writable,write,writelines -{} -{'a': 1} -{'a': 1} -[] -['a', 'b', 'c', '7'] -function('tr') -function('tr', [123, 3, 4]) -function('tr') -function('tr', {}) -function('tr', [123, 3, 4], {}) -auto_rebind -function('tr') -function('tr', [123, 3, 4]) -function('tr') -function('tr', {}) -function('tr', [123, 3, 4], {}) -a: -pa1: -pa2: -pa3: -pa4: -sa: -psa1: -psa2: -psa3: -psa4: -psa5: -psa6: -psa7: -psa8: -psa9: -psaA: -psaB: -psaC: -psar: -s(a): function('Args') -s(pa1): function('Args', ['abcArgsPA1']) -s(pa2): function('Args') -s(pa3): function('Args', ['abcArgsPA3'], {'abcSelfPA3': 'abcSelfPA3Val'}) -s(pa4): function('Args', {'abcSelfPA4': 'abcSelfPA4Val'}) -s(sa): function('SelfArgs') -s(psa1): function('SelfArgs', ['abcArgsPSA1']) -s(psa2): function('SelfArgs') -s(psa3): function('SelfArgs', ['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}) -s(psa4): function('SelfArgs', {'abcSelfPSA4': 'abcSelfPSA4Val'}) -s(psa5): function('SelfArgs', {'abcSelfPSA5': 'abcSelfPSA5Val'}) -s(psa6): function('SelfArgs', ['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'}) -s(psa7): function('SelfArgs', ['abcArgsPSA7']) -s(psa8): function('SelfArgs') -s(psa9): function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'}) -s(psaA): function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'}) -s(psaB): function('SelfArgs', ['abcArgsPSAB']) -s(psaC): function('SelfArgs') -d.sa(): [[], {'f': function('SelfArgs')}] -d.psa1(): [['abcArgsPSA1'], {'f': function('SelfArgs', ['abcArgsPSA1'])}] -d.psa2(): [[], {'f': function('SelfArgs')}] -d.psa3(): [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}] -d.psa4(): [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}] -d.psa5(): [[], {'abcSelfPSA5': 'abcSelfPSA5Val'}] -d.psa6(): [['abcArgsPSA6'], {'abcSelfPSA6': 'abcSelfPSA6Val'}] -d.psa7(): [['abcArgsPSA7'], {'f': function('SelfArgs', ['abcArgsPSA7'])}] -d.psa8(): [[], {'f': function('SelfArgs')}] -d.psa9(): [[], {'f': function('SelfArgs', {'abcSelfPSA9': 'abcSelfPSA9Val'})}] -d.psaA(): [['abcArgsPSAA'], {'f': function('SelfArgs', ['abcArgsPSAA'], {'abcSelfPSAA': 'abcSelfPSAAVal'})}] -d.psaB(): [['abcArgsPSAB'], {'f': function('SelfArgs', ['abcArgsPSAB'])}] -d.psaC(): [[], {'f': function('SelfArgs')}] -a(): !result: [] -pa1(): !result: ['abcArgsPA1'] -pa2(): !result: [] -pa3(): !result: ['abcArgsPA3'] -pa4(): !result: [] -sa(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa1(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa2(): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa3(): !result: [['abcArgsPSA3'], {'abcSelfPSA3': 'abcSelfPSA3Val'}] -psa4(): !result: [[], {'abcSelfPSA4': 'abcSelfPSA4Val'}] -a(42, 43): !result: [42, 43] -pa1(42, 43): !result: ['abcArgsPA1', 42, 43] -pa2(42, 43): !result: [42, 43] -pa3(42, 43): !result: ['abcArgsPA3', 42, 43] -pa4(42, 43): !result: [42, 43] -sa(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa1(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa2(42, 43): !exception: error:('Vim:E725: Calling dict function without Dictionary: SelfArgs',) -psa3(42, 43): !result: [['abcArgsPSA3', 42, 43], {'abcSelfPSA3': 'abcSelfPSA3Val'}] -psa4(42, 43): !result: [[42, 43], {'abcSelfPSA4': 'abcSelfPSA4Val'}] -a(42, self={"20": 1}): !result: [42] -pa1(42, self={"20": 1}): !result: ['abcArgsPA1', 42] -pa2(42, self={"20": 1}): !result: [42] -pa3(42, self={"20": 1}): !result: ['abcArgsPA3', 42] -pa4(42, self={"20": 1}): !result: [42] -sa(42, self={"20": 1}): !result: [[42], {'20': 1}] -psa1(42, self={"20": 1}): !result: [['abcArgsPSA1', 42], {'20': 1}] -psa2(42, self={"20": 1}): !result: [[42], {'20': 1}] -psa3(42, self={"20": 1}): !result: [['abcArgsPSA3', 42], {'20': 1}] -psa4(42, self={"20": 1}): !result: [[42], {'20': 1}] -a(self={"20": 1}): !result: [] -pa1(self={"20": 1}): !result: ['abcArgsPA1'] -pa2(self={"20": 1}): !result: [] -pa3(self={"20": 1}): !result: ['abcArgsPA3'] -pa4(self={"20": 1}): !result: [] -sa(self={"20": 1}): !result: [[], {'20': 1}] -psa1(self={"20": 1}): !result: [['abcArgsPSA1'], {'20': 1}] -psa2(self={"20": 1}): !result: [[], {'20': 1}] -psa3(self={"20": 1}): !result: [['abcArgsPSA3'], {'20': 1}] -psa4(self={"20": 1}): !result: [[], {'20': 1}] -a.args: None -pa1.args: ['abcArgsPA1'] -pa2.args: None -pa3.args: ['abcArgsPA3'] -pa4.args: None -sa.args: None -psa1.args: ['abcArgsPSA1'] -psa2.args: None -psa3.args: ['abcArgsPSA3'] -psa4.args: None -a.self: None -pa1.self: None -pa2.self: None -pa3.self: {'abcSelfPA3': 'abcSelfPA3Val'} -pa4.self: {'abcSelfPA4': 'abcSelfPA4Val'} -sa.self: None -psa1.self: None -psa2.self: None -psa3.self: {'abcSelfPSA3': 'abcSelfPSA3Val'} -psa4.self: {'abcSelfPSA4': 'abcSelfPSA4Val'} -a.name: 'Args' -pa1.name: 'Args' -pa2.name: 'Args' -pa3.name: 'Args' -pa4.name: 'Args' -sa.name: 'SelfArgs' -psa1.name: 'SelfArgs' -psa2.name: 'SelfArgs' -psa3.name: 'SelfArgs' -psa4.name: 'SelfArgs' -a.auto_rebind: 1 -pa1.auto_rebind: 1 -pa2.auto_rebind: 1 -pa3.auto_rebind: 0 -pa4.auto_rebind: 0 -sa.auto_rebind: 1 -psa1.auto_rebind: 1 -psa2.auto_rebind: 1 -psa3.auto_rebind: 0 -psa4.auto_rebind: 0 -psa5.auto_rebind: 0 -psa6.auto_rebind: 0 -psa7.auto_rebind: 1 -psa8.auto_rebind: 1 -psa9.auto_rebind: 1 -psaA.auto_rebind: 1 -psaB.auto_rebind: 1 -psaC.auto_rebind: 1 -' -abcdef -Error detected while processing function RunTest[]..Test: -line : -abcdef -abcA -line : -abcB' -['a', 'dup_a'] -['a', 'a'] -['a', 'b', 'c', 'C'] -[2, 2] -[2, 2] -1 -1 -function('Put') -b'testdir' -test87.in -b'src' -testdir/test87.in -b'testdir' -test87.in -> Output ->> OutputSetattr -del sys.stdout.softspace:(, AttributeError('cannot delete OutputObject attributes',)) ->>> Testing NumberToLong using sys.stdout.softspace = %s -sys.stdout.softspace = []:(, TypeError('expected int() or something supporting coercing to int(), but got list',)) -sys.stdout.softspace = None:(, TypeError('expected int() or something supporting coercing to int(), but got NoneType',)) -sys.stdout.softspace = -1:(, ValueError('number must be greater or equal to zero',)) -<<< Finished ->>> Testing NumberToLong using sys.stderr.softspace = %s -sys.stderr.softspace = []:(, TypeError('expected int() or something supporting coercing to int(), but got list',)) -sys.stderr.softspace = None:(, TypeError('expected int() or something supporting coercing to int(), but got NoneType',)) -sys.stderr.softspace = -1:(, ValueError('number must be greater or equal to zero',)) -<<< Finished -assert sys.stdout.isatty()==False:NOT FAILED -assert sys.stdout.seekable()==False:NOT FAILED -sys.stdout.close():NOT FAILED -sys.stdout.flush():NOT FAILED -assert sys.stderr.isatty()==False:NOT FAILED -assert sys.stderr.seekable()==False:NOT FAILED -sys.stderr.close():NOT FAILED -sys.stderr.flush():NOT FAILED -sys.stdout.attr = None:(, AttributeError('invalid attribute: attr',)) ->> OutputWrite -assert sys.stdout.writable()==True:NOT FAILED -assert sys.stdout.readable()==False:NOT FAILED -assert sys.stderr.writable()==True:NOT FAILED -assert sys.stderr.readable()==False:NOT FAILED -assert sys.stdout.closed()==False:NOT FAILED -assert sys.stderr.closed()==False:NOT FAILED -assert sys.stdout.errors=="strict":NOT FAILED -assert sys.stderr.errors=="strict":NOT FAILED -assert sys.stdout.encoding==sys.stderr.encoding:NOT FAILED -sys.stdout.write(None):(, TypeError("Can't convert 'NoneType' object to str implicitly",)) ->> OutputWriteLines -sys.stdout.writelines(None):(, TypeError("'NoneType' object is not iterable",)) -sys.stdout.writelines([1]):(, TypeError("Can't convert 'int' object to str implicitly",)) ->>> Testing *Iter* using sys.stdout.writelines(%s) -sys.stdout.writelines(FailingIter()):(, NotImplementedError('iter',)) -sys.stdout.writelines(FailingIterNext()):(, NotImplementedError('next',)) -<<< Finished -> VimCommand ->>> Testing StringToChars using vim.command(%s) -vim.command(1):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.command(b"\0"):(, TypeError('expected bytes with no null',)) -vim.command("\0"):(, TypeError('expected bytes with no null',)) -<<< Finished -vim.command("", 2):(, TypeError('command() takes exactly one argument (2 given)',)) -> VimToPython -> VimEval ->>> Testing StringToChars using vim.eval(%s) -vim.eval(1):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.eval(b"\0"):(, TypeError('expected bytes with no null',)) -vim.eval("\0"):(, TypeError('expected bytes with no null',)) -<<< Finished -vim.eval("", FailingTrue()):(, TypeError('function takes exactly 1 argument (2 given)',)) -> VimEvalPy ->>> Testing StringToChars using vim.bindeval(%s) -vim.bindeval(1):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.bindeval(b"\0"):(, TypeError('expected bytes with no null',)) -vim.bindeval("\0"):(, TypeError('expected bytes with no null',)) -<<< Finished -vim.eval("", 2):(, TypeError('function takes exactly 1 argument (2 given)',)) -> VimStrwidth ->>> Testing StringToChars using vim.strwidth(%s) -vim.strwidth(1):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.strwidth(b"\0"):(, TypeError('expected bytes with no null',)) -vim.strwidth("\0"):(, TypeError('expected bytes with no null',)) -<<< Finished -> VimForeachRTP -vim.foreach_rtp(None):(, TypeError("'NoneType' object is not callable",)) -vim.foreach_rtp(NoArgsCall()):(, TypeError('__call__() takes exactly 1 positional argument (2 given)',)) -vim.foreach_rtp(FailingCall()):(, NotImplementedError('call',)) -vim.foreach_rtp(int, 2):(, TypeError('foreach_rtp() takes exactly one argument (2 given)',)) -> import -import xxx_no_such_module_xxx:(, ImportError('No module named xxx_no_such_module_xxx',)) -import failing_import:(, ImportError()) -import failing:(, NotImplementedError()) -> Options ->> OptionsItem -vim.options["abcQ"]:(, KeyError('abcQ',)) -vim.options[""]:(, ValueError('empty keys are not allowed',)) ->>> Testing StringToChars using vim.options[%s] -vim.options[1]:(, TypeError('expected bytes() or str() instance, but got int',)) -vim.options[b"\0"]:(, TypeError('expected bytes with no null',)) -vim.options["\0"]:(, TypeError('expected bytes with no null',)) -<<< Finished ->> OptionsContains ->>> Testing StringToChars using %s in vim.options -1 in vim.options:(, TypeError('expected bytes() or str() instance, but got int',)) -b"\0" in vim.options:(, TypeError('expected bytes with no null',)) -"\0" in vim.options:(, TypeError('expected bytes with no null',)) -<<< Finished -> Dictionary ->> DictionaryConstructor -vim.Dictionary("abcI"):(, ValueError('expected sequence element of size 2, but got sequence of size 1',)) ->> DictionarySetattr -del d.locked:(, AttributeError('cannot delete vim.Dictionary attributes',)) -d.locked = FailingTrue():(, NotImplementedError('bool',)) -vim.vvars.locked = False:(, TypeError('cannot modify fixed dictionary',)) -d.scope = True:(, AttributeError('cannot set attribute scope',)) -d.xxx = True:(, AttributeError('cannot set attribute xxx',)) ->> _DictionaryItem -d.get("a", 2, 3):(, TypeError('function takes at most 2 arguments (3 given)',)) ->>> Testing StringToChars using d.get(%s) -d.get(1):(, TypeError('expected bytes() or str() instance, but got int',)) -d.get(b"\0"):(, TypeError('expected bytes with no null',)) -d.get("\0"):(, TypeError('expected bytes with no null',)) -<<< Finished -d.pop("a"):(, KeyError('a',)) -dl.pop("a"):(, error('dictionary is locked',)) ->> DictionaryContains -"" in d:(, ValueError('empty keys are not allowed',)) -0 in d:(, TypeError('expected bytes() or str() instance, but got int',)) ->> DictionaryIterNext -for i in ned: ned["a"] = 1:(, RuntimeError('hashtab changed during iteration',)) ->> DictionaryAssItem -dl["b"] = 1:(, error('dictionary is locked',)) ->>> Testing StringToChars using d[%s] = 1 -d[1] = 1:(, TypeError('expected bytes() or str() instance, but got int',)) -d[b"\0"] = 1:(, TypeError('expected bytes with no null',)) -d["\0"] = 1:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d["a"] = {%s : 1} -d["a"] = {1 : 1}:(, TypeError('expected bytes() or str() instance, but got int',)) -d["a"] = {b"\0" : 1}:(, TypeError('expected bytes with no null',)) -d["a"] = {"\0" : 1}:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d["a"] = {"abcF" : {%s : 1}} -d["a"] = {"abcF" : {1 : 1}}:(, TypeError('expected bytes() or str() instance, but got int',)) -d["a"] = {"abcF" : {b"\0" : 1}}:(, TypeError('expected bytes with no null',)) -d["a"] = {"abcF" : {"\0" : 1}}:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d["a"] = {"abcF" : Mapping({%s : 1})} -d["a"] = {"abcF" : Mapping({1 : 1})}:(, TypeError('expected bytes() or str() instance, but got int',)) -d["a"] = {"abcF" : Mapping({b"\0" : 1})}:(, TypeError('expected bytes with no null',)) -d["a"] = {"abcF" : Mapping({"\0" : 1})}:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using d["a"] = {"abcF" : %s} -d["a"] = {"abcF" : FailingIter()}:(, TypeError('unable to convert FailingIter to a Vim structure',)) -d["a"] = {"abcF" : FailingIterNext()}:(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s} -d["a"] = {"abcF" : None}:NOT FAILED -d["a"] = {"abcF" : {b"": 1}}:(, ValueError('empty keys are not allowed',)) -d["a"] = {"abcF" : {"": 1}}:(, ValueError('empty keys are not allowed',)) -d["a"] = {"abcF" : FailingMapping()}:(, NotImplementedError('keys',)) -d["a"] = {"abcF" : FailingMappingKey()}:(, NotImplementedError('getitem:mappingkey',)) -d["a"] = {"abcF" : FailingNumber()}:(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using d["a"] = Mapping({%s : 1}) -d["a"] = Mapping({1 : 1}):(, TypeError('expected bytes() or str() instance, but got int',)) -d["a"] = Mapping({b"\0" : 1}):(, TypeError('expected bytes with no null',)) -d["a"] = Mapping({"\0" : 1}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d["a"] = Mapping({"abcG" : {%s : 1}}) -d["a"] = Mapping({"abcG" : {1 : 1}}):(, TypeError('expected bytes() or str() instance, but got int',)) -d["a"] = Mapping({"abcG" : {b"\0" : 1}}):(, TypeError('expected bytes with no null',)) -d["a"] = Mapping({"abcG" : {"\0" : 1}}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d["a"] = Mapping({"abcG" : Mapping({%s : 1})}) -d["a"] = Mapping({"abcG" : Mapping({1 : 1})}):(, TypeError('expected bytes() or str() instance, but got int',)) -d["a"] = Mapping({"abcG" : Mapping({b"\0" : 1})}):(, TypeError('expected bytes with no null',)) -d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s}) -d["a"] = Mapping({"abcG" : FailingIter()}):(, TypeError('unable to convert FailingIter to a Vim structure',)) -d["a"] = Mapping({"abcG" : FailingIterNext()}):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s}) -d["a"] = Mapping({"abcG" : None}):NOT FAILED -d["a"] = Mapping({"abcG" : {b"": 1}}):(, ValueError('empty keys are not allowed',)) -d["a"] = Mapping({"abcG" : {"": 1}}):(, ValueError('empty keys are not allowed',)) -d["a"] = Mapping({"abcG" : FailingMapping()}):(, NotImplementedError('keys',)) -d["a"] = Mapping({"abcG" : FailingMappingKey()}):(, NotImplementedError('getitem:mappingkey',)) -d["a"] = Mapping({"abcG" : FailingNumber()}):(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using d["a"] = %s -d["a"] = FailingIter():(, TypeError('unable to convert FailingIter to a Vim structure',)) -d["a"] = FailingIterNext():(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d["a"] = %s -d["a"] = None:NOT FAILED -d["a"] = {b"": 1}:(, ValueError('empty keys are not allowed',)) -d["a"] = {"": 1}:(, ValueError('empty keys are not allowed',)) -d["a"] = FailingMapping():(, NotImplementedError('keys',)) -d["a"] = FailingMappingKey():(, NotImplementedError('getitem:mappingkey',)) -d["a"] = FailingNumber():(, NotImplementedError('int',)) -<<< Finished ->> DictionaryUpdate ->>> kwargs ->>> iter -d.update(FailingMapping()):(, NotImplementedError('keys',)) -d.update([FailingIterNext()]):(, NotImplementedError('next',)) -d.update([FailingIterNextN(1)]):(, NotImplementedError('next N',)) ->>> Testing *Iter* using d.update(%s) -d.update(FailingIter()):(, NotImplementedError('iter',)) -d.update(FailingIterNext()):(, NotImplementedError('next',)) -<<< Finished ->>> Testing StringToChars using d.update({%s : 1}) -d.update({1 : 1}):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update({b"\0" : 1}):(, TypeError('expected bytes with no null',)) -d.update({"\0" : 1}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update({"abcF" : {%s : 1}}) -d.update({"abcF" : {1 : 1}}):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update({"abcF" : {b"\0" : 1}}):(, TypeError('expected bytes with no null',)) -d.update({"abcF" : {"\0" : 1}}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update({"abcF" : Mapping({%s : 1})}) -d.update({"abcF" : Mapping({1 : 1})}):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update({"abcF" : Mapping({b"\0" : 1})}):(, TypeError('expected bytes with no null',)) -d.update({"abcF" : Mapping({"\0" : 1})}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using d.update({"abcF" : %s}) -d.update({"abcF" : FailingIter()}):(, TypeError('unable to convert FailingIter to a Vim structure',)) -d.update({"abcF" : FailingIterNext()}):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d.update({"abcF" : %s}) -d.update({"abcF" : None}):NOT FAILED -d.update({"abcF" : {b"": 1}}):(, ValueError('empty keys are not allowed',)) -d.update({"abcF" : {"": 1}}):(, ValueError('empty keys are not allowed',)) -d.update({"abcF" : FailingMapping()}):(, NotImplementedError('keys',)) -d.update({"abcF" : FailingMappingKey()}):(, NotImplementedError('getitem:mappingkey',)) -d.update({"abcF" : FailingNumber()}):(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using d.update(Mapping({%s : 1})) -d.update(Mapping({1 : 1})):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update(Mapping({b"\0" : 1})):(, TypeError('expected bytes with no null',)) -d.update(Mapping({"\0" : 1})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update(Mapping({"abcG" : {%s : 1}})) -d.update(Mapping({"abcG" : {1 : 1}})):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update(Mapping({"abcG" : {b"\0" : 1}})):(, TypeError('expected bytes with no null',)) -d.update(Mapping({"abcG" : {"\0" : 1}})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update(Mapping({"abcG" : Mapping({%s : 1})})) -d.update(Mapping({"abcG" : Mapping({1 : 1})})):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update(Mapping({"abcG" : Mapping({b"\0" : 1})})):(, TypeError('expected bytes with no null',)) -d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using d.update(Mapping({"abcG" : %s})) -d.update(Mapping({"abcG" : FailingIter()})):(, TypeError('unable to convert FailingIter to a Vim structure',)) -d.update(Mapping({"abcG" : FailingIterNext()})):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s})) -d.update(Mapping({"abcG" : None})):NOT FAILED -d.update(Mapping({"abcG" : {b"": 1}})):(, ValueError('empty keys are not allowed',)) -d.update(Mapping({"abcG" : {"": 1}})):(, ValueError('empty keys are not allowed',)) -d.update(Mapping({"abcG" : FailingMapping()})):(, NotImplementedError('keys',)) -d.update(Mapping({"abcG" : FailingMappingKey()})):(, NotImplementedError('getitem:mappingkey',)) -d.update(Mapping({"abcG" : FailingNumber()})):(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using d.update(%s) -d.update(FailingIter()):(, NotImplementedError('iter',)) -d.update(FailingIterNext()):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d.update(%s) -d.update(None):(, TypeError("'NoneType' object is not iterable",)) -d.update({b"": 1}):(, ValueError('empty keys are not allowed',)) -d.update({"": 1}):(, ValueError('empty keys are not allowed',)) -d.update(FailingMapping()):(, NotImplementedError('keys',)) -d.update(FailingMappingKey()):(, NotImplementedError('getitem:mappingkey',)) -d.update(FailingNumber()):(, TypeError("'FailingNumber' object is not iterable",)) -<<< Finished ->>> Testing StringToChars using d.update(((%s, 0),)) -d.update(((1, 0),)):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update(((b"\0", 0),)):(, TypeError('expected bytes with no null',)) -d.update((("\0", 0),)):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update((("a", {%s : 1}),)) -d.update((("a", {1 : 1}),)):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update((("a", {b"\0" : 1}),)):(, TypeError('expected bytes with no null',)) -d.update((("a", {"\0" : 1}),)):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update((("a", {"abcF" : {%s : 1}}),)) -d.update((("a", {"abcF" : {1 : 1}}),)):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update((("a", {"abcF" : {b"\0" : 1}}),)):(, TypeError('expected bytes with no null',)) -d.update((("a", {"abcF" : {"\0" : 1}}),)):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update((("a", {"abcF" : Mapping({%s : 1})}),)) -d.update((("a", {"abcF" : Mapping({1 : 1})}),)):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update((("a", {"abcF" : Mapping({b"\0" : 1})}),)):(, TypeError('expected bytes with no null',)) -d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using d.update((("a", {"abcF" : %s}),)) -d.update((("a", {"abcF" : FailingIter()}),)):(, TypeError('unable to convert FailingIter to a Vim structure',)) -d.update((("a", {"abcF" : FailingIterNext()}),)):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),)) -d.update((("a", {"abcF" : None}),)):(, error("failed to add key 'a' to dictionary",)) -d.update((("a", {"abcF" : {b"": 1}}),)):(, ValueError('empty keys are not allowed',)) -d.update((("a", {"abcF" : {"": 1}}),)):(, ValueError('empty keys are not allowed',)) -d.update((("a", {"abcF" : FailingMapping()}),)):(, NotImplementedError('keys',)) -d.update((("a", {"abcF" : FailingMappingKey()}),)):(, NotImplementedError('getitem:mappingkey',)) -d.update((("a", {"abcF" : FailingNumber()}),)):(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using d.update((("a", Mapping({%s : 1})),)) -d.update((("a", Mapping({1 : 1})),)):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update((("a", Mapping({b"\0" : 1})),)):(, TypeError('expected bytes with no null',)) -d.update((("a", Mapping({"\0" : 1})),)):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : {%s : 1}})),)) -d.update((("a", Mapping({"abcG" : {1 : 1}})),)):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update((("a", Mapping({"abcG" : {b"\0" : 1}})),)):(, TypeError('expected bytes with no null',)) -d.update((("a", Mapping({"abcG" : {"\0" : 1}})),)):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using d.update((("a", Mapping({"abcG" : Mapping({%s : 1})})),)) -d.update((("a", Mapping({"abcG" : Mapping({1 : 1})})),)):(, TypeError('expected bytes() or str() instance, but got int',)) -d.update((("a", Mapping({"abcG" : Mapping({b"\0" : 1})})),)):(, TypeError('expected bytes with no null',)) -d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),)) -d.update((("a", Mapping({"abcG" : FailingIter()})),)):(, TypeError('unable to convert FailingIter to a Vim structure',)) -d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),)) -d.update((("a", Mapping({"abcG" : None})),)):(, error("failed to add key 'a' to dictionary",)) -d.update((("a", Mapping({"abcG" : {b"": 1}})),)):(, ValueError('empty keys are not allowed',)) -d.update((("a", Mapping({"abcG" : {"": 1}})),)):(, ValueError('empty keys are not allowed',)) -d.update((("a", Mapping({"abcG" : FailingMapping()})),)):(, NotImplementedError('keys',)) -d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):(, NotImplementedError('getitem:mappingkey',)) -d.update((("a", Mapping({"abcG" : FailingNumber()})),)):(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using d.update((("a", %s),)) -d.update((("a", FailingIter()),)):(, TypeError('unable to convert FailingIter to a Vim structure',)) -d.update((("a", FailingIterNext()),)):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using d.update((("a", %s),)) -d.update((("a", None),)):(, error("failed to add key 'a' to dictionary",)) -d.update((("a", {b"": 1}),)):(, ValueError('empty keys are not allowed',)) -d.update((("a", {"": 1}),)):(, ValueError('empty keys are not allowed',)) -d.update((("a", FailingMapping()),)):(, NotImplementedError('keys',)) -d.update((("a", FailingMappingKey()),)):(, NotImplementedError('getitem:mappingkey',)) -d.update((("a", FailingNumber()),)):(, NotImplementedError('int',)) -<<< Finished ->> DictionaryPopItem -d.popitem(1, 2):(, TypeError('popitem() takes no arguments (2 given)',)) ->> DictionaryHasKey -d.has_key():(, TypeError('has_key() takes exactly one argument (0 given)',)) -> List ->> ListConstructor -vim.List(1, 2):(, TypeError('function takes at most 1 argument (2 given)',)) -vim.List(a=1):(, TypeError('list constructor does not accept keyword arguments',)) ->>> Testing *Iter* using vim.List(%s) -vim.List(FailingIter()):(, NotImplementedError('iter',)) -vim.List(FailingIterNext()):(, NotImplementedError('next',)) -<<< Finished ->>> Testing StringToChars using vim.List([{%s : 1}]) -vim.List([{1 : 1}]):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.List([{b"\0" : 1}]):(, TypeError('expected bytes with no null',)) -vim.List([{"\0" : 1}]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using vim.List([{"abcF" : {%s : 1}}]) -vim.List([{"abcF" : {1 : 1}}]):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.List([{"abcF" : {b"\0" : 1}}]):(, TypeError('expected bytes with no null',)) -vim.List([{"abcF" : {"\0" : 1}}]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using vim.List([{"abcF" : Mapping({%s : 1})}]) -vim.List([{"abcF" : Mapping({1 : 1})}]):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.List([{"abcF" : Mapping({b"\0" : 1})}]):(, TypeError('expected bytes with no null',)) -vim.List([{"abcF" : Mapping({"\0" : 1})}]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using vim.List([{"abcF" : %s}]) -vim.List([{"abcF" : FailingIter()}]):(, TypeError('unable to convert FailingIter to a Vim structure',)) -vim.List([{"abcF" : FailingIterNext()}]):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}]) -vim.List([{"abcF" : None}]):NOT FAILED -vim.List([{"abcF" : {b"": 1}}]):(, ValueError('empty keys are not allowed',)) -vim.List([{"abcF" : {"": 1}}]):(, ValueError('empty keys are not allowed',)) -vim.List([{"abcF" : FailingMapping()}]):(, NotImplementedError('keys',)) -vim.List([{"abcF" : FailingMappingKey()}]):(, NotImplementedError('getitem:mappingkey',)) -vim.List([{"abcF" : FailingNumber()}]):(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using vim.List([Mapping({%s : 1})]) -vim.List([Mapping({1 : 1})]):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.List([Mapping({b"\0" : 1})]):(, TypeError('expected bytes with no null',)) -vim.List([Mapping({"\0" : 1})]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using vim.List([Mapping({"abcG" : {%s : 1}})]) -vim.List([Mapping({"abcG" : {1 : 1}})]):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.List([Mapping({"abcG" : {b"\0" : 1}})]):(, TypeError('expected bytes with no null',)) -vim.List([Mapping({"abcG" : {"\0" : 1}})]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using vim.List([Mapping({"abcG" : Mapping({%s : 1})})]) -vim.List([Mapping({"abcG" : Mapping({1 : 1})})]):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.List([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(, TypeError('expected bytes with no null',)) -vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})]) -vim.List([Mapping({"abcG" : FailingIter()})]):(, TypeError('unable to convert FailingIter to a Vim structure',)) -vim.List([Mapping({"abcG" : FailingIterNext()})]):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})]) -vim.List([Mapping({"abcG" : None})]):NOT FAILED -vim.List([Mapping({"abcG" : {b"": 1}})]):(, ValueError('empty keys are not allowed',)) -vim.List([Mapping({"abcG" : {"": 1}})]):(, ValueError('empty keys are not allowed',)) -vim.List([Mapping({"abcG" : FailingMapping()})]):(, NotImplementedError('keys',)) -vim.List([Mapping({"abcG" : FailingMappingKey()})]):(, NotImplementedError('getitem:mappingkey',)) -vim.List([Mapping({"abcG" : FailingNumber()})]):(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using vim.List([%s]) -vim.List([FailingIter()]):(, TypeError('unable to convert FailingIter to a Vim structure',)) -vim.List([FailingIterNext()]):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using vim.List([%s]) -vim.List([None]):NOT FAILED -vim.List([{b"": 1}]):(, ValueError('empty keys are not allowed',)) -vim.List([{"": 1}]):(, ValueError('empty keys are not allowed',)) -vim.List([FailingMapping()]):(, NotImplementedError('keys',)) -vim.List([FailingMappingKey()]):(, NotImplementedError('getitem:mappingkey',)) -vim.List([FailingNumber()]):(, NotImplementedError('int',)) -<<< Finished ->> ListItem -l[1000]:(, IndexError('list index out of range',)) ->> ListAssItem -ll[1] = 2:(, error('list is locked',)) -l[1000] = 3:(, IndexError('list index out of range',)) ->> ListAssSlice -ll[1:100] = "abcJ":(, error('list is locked',)) ->>> Testing *Iter* using l[:] = %s -l[:] = FailingIter():(, NotImplementedError('iter',)) -l[:] = FailingIterNext():(, NotImplementedError('next',)) -<<< Finished -nel[1:10:2] = "abcK":(, ValueError('attempt to assign sequence of size greater than 2 to extended slice',)) -(b'a', b'b', b'c', b'O') -nel[1:10:2] = "a":(, ValueError('attempt to assign sequence of size 1 to extended slice of size 2',)) -(b'a', b'b', b'c', b'O') -nel[1:1:-1] = "a":(, ValueError('attempt to assign sequence of size greater than 0 to extended slice',)) -(b'a', b'b', b'c', b'O') -nel[:] = FailingIterNextN(2):(, NotImplementedError('next N',)) -(b'a', b'b', b'c', b'O') ->>> Testing StringToChars using l[:] = [{%s : 1}] -l[:] = [{1 : 1}]:(, TypeError('expected bytes() or str() instance, but got int',)) -l[:] = [{b"\0" : 1}]:(, TypeError('expected bytes with no null',)) -l[:] = [{"\0" : 1}]:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l[:] = [{"abcF" : {%s : 1}}] -l[:] = [{"abcF" : {1 : 1}}]:(, TypeError('expected bytes() or str() instance, but got int',)) -l[:] = [{"abcF" : {b"\0" : 1}}]:(, TypeError('expected bytes with no null',)) -l[:] = [{"abcF" : {"\0" : 1}}]:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l[:] = [{"abcF" : Mapping({%s : 1})}] -l[:] = [{"abcF" : Mapping({1 : 1})}]:(, TypeError('expected bytes() or str() instance, but got int',)) -l[:] = [{"abcF" : Mapping({b"\0" : 1})}]:(, TypeError('expected bytes with no null',)) -l[:] = [{"abcF" : Mapping({"\0" : 1})}]:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using l[:] = [{"abcF" : %s}] -l[:] = [{"abcF" : FailingIter()}]:(, TypeError('unable to convert FailingIter to a Vim structure',)) -l[:] = [{"abcF" : FailingIterNext()}]:(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}] -l[:] = [{"abcF" : None}]:NOT FAILED -l[:] = [{"abcF" : {b"": 1}}]:(, ValueError('empty keys are not allowed',)) -l[:] = [{"abcF" : {"": 1}}]:(, ValueError('empty keys are not allowed',)) -l[:] = [{"abcF" : FailingMapping()}]:(, NotImplementedError('keys',)) -l[:] = [{"abcF" : FailingMappingKey()}]:(, NotImplementedError('getitem:mappingkey',)) -l[:] = [{"abcF" : FailingNumber()}]:(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using l[:] = [Mapping({%s : 1})] -l[:] = [Mapping({1 : 1})]:(, TypeError('expected bytes() or str() instance, but got int',)) -l[:] = [Mapping({b"\0" : 1})]:(, TypeError('expected bytes with no null',)) -l[:] = [Mapping({"\0" : 1})]:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l[:] = [Mapping({"abcG" : {%s : 1}})] -l[:] = [Mapping({"abcG" : {1 : 1}})]:(, TypeError('expected bytes() or str() instance, but got int',)) -l[:] = [Mapping({"abcG" : {b"\0" : 1}})]:(, TypeError('expected bytes with no null',)) -l[:] = [Mapping({"abcG" : {"\0" : 1}})]:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l[:] = [Mapping({"abcG" : Mapping({%s : 1})})] -l[:] = [Mapping({"abcG" : Mapping({1 : 1})})]:(, TypeError('expected bytes() or str() instance, but got int',)) -l[:] = [Mapping({"abcG" : Mapping({b"\0" : 1})})]:(, TypeError('expected bytes with no null',)) -l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})] -l[:] = [Mapping({"abcG" : FailingIter()})]:(, TypeError('unable to convert FailingIter to a Vim structure',)) -l[:] = [Mapping({"abcG" : FailingIterNext()})]:(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})] -l[:] = [Mapping({"abcG" : None})]:NOT FAILED -l[:] = [Mapping({"abcG" : {b"": 1}})]:(, ValueError('empty keys are not allowed',)) -l[:] = [Mapping({"abcG" : {"": 1}})]:(, ValueError('empty keys are not allowed',)) -l[:] = [Mapping({"abcG" : FailingMapping()})]:(, NotImplementedError('keys',)) -l[:] = [Mapping({"abcG" : FailingMappingKey()})]:(, NotImplementedError('getitem:mappingkey',)) -l[:] = [Mapping({"abcG" : FailingNumber()})]:(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using l[:] = [%s] -l[:] = [FailingIter()]:(, TypeError('unable to convert FailingIter to a Vim structure',)) -l[:] = [FailingIterNext()]:(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using l[:] = [%s] -l[:] = [None]:NOT FAILED -l[:] = [{b"": 1}]:(, ValueError('empty keys are not allowed',)) -l[:] = [{"": 1}]:(, ValueError('empty keys are not allowed',)) -l[:] = [FailingMapping()]:(, NotImplementedError('keys',)) -l[:] = [FailingMappingKey()]:(, NotImplementedError('getitem:mappingkey',)) -l[:] = [FailingNumber()]:(, NotImplementedError('int',)) -<<< Finished ->> ListConcatInPlace ->>> Testing *Iter* using l.extend(%s) -l.extend(FailingIter()):(, NotImplementedError('iter',)) -l.extend(FailingIterNext()):(, NotImplementedError('next',)) -<<< Finished ->>> Testing StringToChars using l.extend([{%s : 1}]) -l.extend([{1 : 1}]):(, TypeError('expected bytes() or str() instance, but got int',)) -l.extend([{b"\0" : 1}]):(, TypeError('expected bytes with no null',)) -l.extend([{"\0" : 1}]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l.extend([{"abcF" : {%s : 1}}]) -l.extend([{"abcF" : {1 : 1}}]):(, TypeError('expected bytes() or str() instance, but got int',)) -l.extend([{"abcF" : {b"\0" : 1}}]):(, TypeError('expected bytes with no null',)) -l.extend([{"abcF" : {"\0" : 1}}]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l.extend([{"abcF" : Mapping({%s : 1})}]) -l.extend([{"abcF" : Mapping({1 : 1})}]):(, TypeError('expected bytes() or str() instance, but got int',)) -l.extend([{"abcF" : Mapping({b"\0" : 1})}]):(, TypeError('expected bytes with no null',)) -l.extend([{"abcF" : Mapping({"\0" : 1})}]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using l.extend([{"abcF" : %s}]) -l.extend([{"abcF" : FailingIter()}]):(, TypeError('unable to convert FailingIter to a Vim structure',)) -l.extend([{"abcF" : FailingIterNext()}]):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}]) -l.extend([{"abcF" : None}]):NOT FAILED -l.extend([{"abcF" : {b"": 1}}]):(, ValueError('empty keys are not allowed',)) -l.extend([{"abcF" : {"": 1}}]):(, ValueError('empty keys are not allowed',)) -l.extend([{"abcF" : FailingMapping()}]):(, NotImplementedError('keys',)) -l.extend([{"abcF" : FailingMappingKey()}]):(, NotImplementedError('getitem:mappingkey',)) -l.extend([{"abcF" : FailingNumber()}]):(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using l.extend([Mapping({%s : 1})]) -l.extend([Mapping({1 : 1})]):(, TypeError('expected bytes() or str() instance, but got int',)) -l.extend([Mapping({b"\0" : 1})]):(, TypeError('expected bytes with no null',)) -l.extend([Mapping({"\0" : 1})]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l.extend([Mapping({"abcG" : {%s : 1}})]) -l.extend([Mapping({"abcG" : {1 : 1}})]):(, TypeError('expected bytes() or str() instance, but got int',)) -l.extend([Mapping({"abcG" : {b"\0" : 1}})]):(, TypeError('expected bytes with no null',)) -l.extend([Mapping({"abcG" : {"\0" : 1}})]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using l.extend([Mapping({"abcG" : Mapping({%s : 1})})]) -l.extend([Mapping({"abcG" : Mapping({1 : 1})})]):(, TypeError('expected bytes() or str() instance, but got int',)) -l.extend([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(, TypeError('expected bytes with no null',)) -l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})]) -l.extend([Mapping({"abcG" : FailingIter()})]):(, TypeError('unable to convert FailingIter to a Vim structure',)) -l.extend([Mapping({"abcG" : FailingIterNext()})]):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})]) -l.extend([Mapping({"abcG" : None})]):NOT FAILED -l.extend([Mapping({"abcG" : {b"": 1}})]):(, ValueError('empty keys are not allowed',)) -l.extend([Mapping({"abcG" : {"": 1}})]):(, ValueError('empty keys are not allowed',)) -l.extend([Mapping({"abcG" : FailingMapping()})]):(, NotImplementedError('keys',)) -l.extend([Mapping({"abcG" : FailingMappingKey()})]):(, NotImplementedError('getitem:mappingkey',)) -l.extend([Mapping({"abcG" : FailingNumber()})]):(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using l.extend([%s]) -l.extend([FailingIter()]):(, TypeError('unable to convert FailingIter to a Vim structure',)) -l.extend([FailingIterNext()]):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using l.extend([%s]) -l.extend([None]):NOT FAILED -l.extend([{b"": 1}]):(, ValueError('empty keys are not allowed',)) -l.extend([{"": 1}]):(, ValueError('empty keys are not allowed',)) -l.extend([FailingMapping()]):(, NotImplementedError('keys',)) -l.extend([FailingMappingKey()]):(, NotImplementedError('getitem:mappingkey',)) -l.extend([FailingNumber()]):(, NotImplementedError('int',)) -<<< Finished ->> ListSetattr -del l.locked:(, AttributeError('cannot delete vim.List attributes',)) -l.locked = FailingTrue():(, NotImplementedError('bool',)) -l.xxx = True:(, AttributeError('cannot set attribute xxx',)) -> Function ->> FunctionConstructor ->>> FunctionConstructor -vim.Function("123"):(, ValueError('unnamed function 123 does not exist',)) -vim.Function("xxx_non_existent_function_xxx"):(, ValueError('function xxx_non_existent_function_xxx does not exist',)) -vim.Function("xxx#non#existent#function#xxx"):NOT FAILED -vim.Function("xxx_non_existent_function_xxx2", args=[]):(, ValueError('function xxx_non_existent_function_xxx2 does not exist',)) -vim.Function("xxx_non_existent_function_xxx3", self={}):(, ValueError('function xxx_non_existent_function_xxx3 does not exist',)) -vim.Function("xxx_non_existent_function_xxx4", args=[], self={}):(, ValueError('function xxx_non_existent_function_xxx4 does not exist',)) ->>> FunctionNew -vim.Function("tr", self="abcFuncSelf"):(, AttributeError('keys',)) -vim.Function("tr", args=427423):(, TypeError('unable to convert int to a Vim list',)) -vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):(, AttributeError('keys',)) -vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):(, AttributeError('keys',)) -vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):(, AttributeError('keys',)) -vim.Function("tr", ""):(, TypeError('function takes exactly 1 argument (2 given)',)) ->> FunctionCall ->>> Testing StringToChars using f({%s : 1}) -f({1 : 1}):(, TypeError('expected bytes() or str() instance, but got int',)) -f({b"\0" : 1}):(, TypeError('expected bytes with no null',)) -f({"\0" : 1}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using f({"abcF" : {%s : 1}}) -f({"abcF" : {1 : 1}}):(, TypeError('expected bytes() or str() instance, but got int',)) -f({"abcF" : {b"\0" : 1}}):(, TypeError('expected bytes with no null',)) -f({"abcF" : {"\0" : 1}}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using f({"abcF" : Mapping({%s : 1})}) -f({"abcF" : Mapping({1 : 1})}):(, TypeError('expected bytes() or str() instance, but got int',)) -f({"abcF" : Mapping({b"\0" : 1})}):(, TypeError('expected bytes with no null',)) -f({"abcF" : Mapping({"\0" : 1})}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using f({"abcF" : %s}) -f({"abcF" : FailingIter()}):(, TypeError('unable to convert FailingIter to a Vim structure',)) -f({"abcF" : FailingIterNext()}):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using f({"abcF" : %s}) -f({"abcF" : None}):NOT FAILED -f({"abcF" : {b"": 1}}):(, ValueError('empty keys are not allowed',)) -f({"abcF" : {"": 1}}):(, ValueError('empty keys are not allowed',)) -f({"abcF" : FailingMapping()}):(, NotImplementedError('keys',)) -f({"abcF" : FailingMappingKey()}):(, NotImplementedError('getitem:mappingkey',)) -f({"abcF" : FailingNumber()}):(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using f(Mapping({%s : 1})) -f(Mapping({1 : 1})):(, TypeError('expected bytes() or str() instance, but got int',)) -f(Mapping({b"\0" : 1})):(, TypeError('expected bytes with no null',)) -f(Mapping({"\0" : 1})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using f(Mapping({"abcG" : {%s : 1}})) -f(Mapping({"abcG" : {1 : 1}})):(, TypeError('expected bytes() or str() instance, but got int',)) -f(Mapping({"abcG" : {b"\0" : 1}})):(, TypeError('expected bytes with no null',)) -f(Mapping({"abcG" : {"\0" : 1}})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using f(Mapping({"abcG" : Mapping({%s : 1})})) -f(Mapping({"abcG" : Mapping({1 : 1})})):(, TypeError('expected bytes() or str() instance, but got int',)) -f(Mapping({"abcG" : Mapping({b"\0" : 1})})):(, TypeError('expected bytes with no null',)) -f(Mapping({"abcG" : Mapping({"\0" : 1})})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using f(Mapping({"abcG" : %s})) -f(Mapping({"abcG" : FailingIter()})):(, TypeError('unable to convert FailingIter to a Vim structure',)) -f(Mapping({"abcG" : FailingIterNext()})):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s})) -f(Mapping({"abcG" : None})):NOT FAILED -f(Mapping({"abcG" : {b"": 1}})):(, ValueError('empty keys are not allowed',)) -f(Mapping({"abcG" : {"": 1}})):(, ValueError('empty keys are not allowed',)) -f(Mapping({"abcG" : FailingMapping()})):(, NotImplementedError('keys',)) -f(Mapping({"abcG" : FailingMappingKey()})):(, NotImplementedError('getitem:mappingkey',)) -f(Mapping({"abcG" : FailingNumber()})):(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using f(%s) -f(FailingIter()):(, TypeError('unable to convert FailingIter to a Vim structure',)) -f(FailingIterNext()):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using f(%s) -f(None):NOT FAILED -f({b"": 1}):(, ValueError('empty keys are not allowed',)) -f({"": 1}):(, ValueError('empty keys are not allowed',)) -f(FailingMapping()):(, NotImplementedError('keys',)) -f(FailingMappingKey()):(, NotImplementedError('getitem:mappingkey',)) -f(FailingNumber()):(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using fd(self={%s : 1}) -fd(self={1 : 1}):(, TypeError('expected bytes() or str() instance, but got int',)) -fd(self={b"\0" : 1}):(, TypeError('expected bytes with no null',)) -fd(self={"\0" : 1}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using fd(self={"abcF" : {%s : 1}}) -fd(self={"abcF" : {1 : 1}}):(, TypeError('expected bytes() or str() instance, but got int',)) -fd(self={"abcF" : {b"\0" : 1}}):(, TypeError('expected bytes with no null',)) -fd(self={"abcF" : {"\0" : 1}}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using fd(self={"abcF" : Mapping({%s : 1})}) -fd(self={"abcF" : Mapping({1 : 1})}):(, TypeError('expected bytes() or str() instance, but got int',)) -fd(self={"abcF" : Mapping({b"\0" : 1})}):(, TypeError('expected bytes with no null',)) -fd(self={"abcF" : Mapping({"\0" : 1})}):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using fd(self={"abcF" : %s}) -fd(self={"abcF" : FailingIter()}):(, TypeError('unable to convert FailingIter to a Vim structure',)) -fd(self={"abcF" : FailingIterNext()}):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using fd(self={"abcF" : %s}) -fd(self={"abcF" : None}):NOT FAILED -fd(self={"abcF" : {b"": 1}}):(, ValueError('empty keys are not allowed',)) -fd(self={"abcF" : {"": 1}}):(, ValueError('empty keys are not allowed',)) -fd(self={"abcF" : FailingMapping()}):(, NotImplementedError('keys',)) -fd(self={"abcF" : FailingMappingKey()}):(, NotImplementedError('getitem:mappingkey',)) -fd(self={"abcF" : FailingNumber()}):(, NotImplementedError('int',)) -<<< Finished ->>> Testing StringToChars using fd(self=Mapping({%s : 1})) -fd(self=Mapping({1 : 1})):(, TypeError('expected bytes() or str() instance, but got int',)) -fd(self=Mapping({b"\0" : 1})):(, TypeError('expected bytes with no null',)) -fd(self=Mapping({"\0" : 1})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using fd(self=Mapping({"abcG" : {%s : 1}})) -fd(self=Mapping({"abcG" : {1 : 1}})):(, TypeError('expected bytes() or str() instance, but got int',)) -fd(self=Mapping({"abcG" : {b"\0" : 1}})):(, TypeError('expected bytes with no null',)) -fd(self=Mapping({"abcG" : {"\0" : 1}})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing StringToChars using fd(self=Mapping({"abcG" : Mapping({%s : 1})})) -fd(self=Mapping({"abcG" : Mapping({1 : 1})})):(, TypeError('expected bytes() or str() instance, but got int',)) -fd(self=Mapping({"abcG" : Mapping({b"\0" : 1})})):(, TypeError('expected bytes with no null',)) -fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):(, TypeError('expected bytes with no null',)) -<<< Finished ->>> Testing *Iter* using fd(self=Mapping({"abcG" : %s})) -fd(self=Mapping({"abcG" : FailingIter()})):(, TypeError('unable to convert FailingIter to a Vim structure',)) -fd(self=Mapping({"abcG" : FailingIterNext()})):(, NotImplementedError('next',)) -<<< Finished ->>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s})) -fd(self=Mapping({"abcG" : None})):NOT FAILED -fd(self=Mapping({"abcG" : {b"": 1}})):(, ValueError('empty keys are not allowed',)) -fd(self=Mapping({"abcG" : {"": 1}})):(, ValueError('empty keys are not allowed',)) -fd(self=Mapping({"abcG" : FailingMapping()})):(, NotImplementedError('keys',)) -fd(self=Mapping({"abcG" : FailingMappingKey()})):(, NotImplementedError('getitem:mappingkey',)) -fd(self=Mapping({"abcG" : FailingNumber()})):(, NotImplementedError('int',)) -<<< Finished ->>> Testing *Iter* using fd(self=%s) -fd(self=FailingIter()):(, TypeError('unable to convert FailingIter to a Vim dictionary',)) -fd(self=FailingIterNext()):(, TypeError('unable to convert FailingIterNext to a Vim dictionary',)) -<<< Finished ->>> Testing ConvertFromPyObject using fd(self=%s) -fd(self=None):(, TypeError('unable to convert NoneType to a Vim dictionary',)) -fd(self={b"": 1}):(, ValueError('empty keys are not allowed',)) -fd(self={"": 1}):(, ValueError('empty keys are not allowed',)) -fd(self=FailingMapping()):(, NotImplementedError('keys',)) -fd(self=FailingMappingKey()):(, NotImplementedError('getitem:mappingkey',)) -fd(self=FailingNumber()):(, TypeError('unable to convert FailingNumber to a Vim dictionary',)) -<<< Finished ->>> Testing ConvertFromPyMapping using fd(self=%s) -fd(self=[]):(, AttributeError('keys',)) -<<< Finished -> TabPage ->> TabPageAttr -vim.current.tabpage.xxx:(, AttributeError("'vim.tabpage' object has no attribute 'xxx'",)) -> TabList ->> TabListItem -vim.tabpages[1000]:(, IndexError('no such tab page',)) -> Window ->> WindowAttr -vim.current.window.xxx:(, AttributeError("'vim.window' object has no attribute 'xxx'",)) ->> WindowSetattr -vim.current.window.buffer = 0:(, TypeError('readonly attribute: buffer',)) -vim.current.window.cursor = (100000000, 100000000):(, error('cursor position outside buffer',)) -vim.current.window.cursor = True:(, TypeError('argument must be 2-item sequence, not bool',)) ->>> Testing NumberToLong using vim.current.window.height = %s -vim.current.window.height = []:(, TypeError('expected int() or something supporting coercing to int(), but got list',)) -vim.current.window.height = None:(, TypeError('expected int() or something supporting coercing to int(), but got NoneType',)) -vim.current.window.height = -1:(, ValueError('number must be greater or equal to zero',)) -<<< Finished ->>> Testing NumberToLong using vim.current.window.width = %s -vim.current.window.width = []:(, TypeError('expected int() or something supporting coercing to int(), but got list',)) -vim.current.window.width = None:(, TypeError('expected int() or something supporting coercing to int(), but got NoneType',)) -vim.current.window.width = -1:(, ValueError('number must be greater or equal to zero',)) -<<< Finished -vim.current.window.xxxxxx = True:(, AttributeError('xxxxxx',)) -> WinList ->> WinListItem -vim.windows[1000]:(, IndexError('no such window',)) -> Buffer ->> StringToLine (indirect) -vim.current.buffer[0] = "\na":(, error('string cannot contain newlines',)) -vim.current.buffer[0] = b"\na":(, error('string cannot contain newlines',)) ->> SetBufferLine (indirect) -vim.current.buffer[0] = True:(, TypeError('bad argument type for built-in operation',)) ->> SetBufferLineList (indirect) -vim.current.buffer[:] = True:(, TypeError('bad argument type for built-in operation',)) -vim.current.buffer[:] = ["\na", "bc"]:(, error('string cannot contain newlines',)) ->> InsertBufferLines (indirect) -vim.current.buffer.append(None):(, TypeError('bad argument type for built-in operation',)) -vim.current.buffer.append(["\na", "bc"]):(, error('string cannot contain newlines',)) -vim.current.buffer.append("\nbc"):(, error('string cannot contain newlines',)) ->> RBItem -vim.current.buffer[100000000]:(, IndexError('line number out of range',)) ->> RBAsItem -vim.current.buffer[100000000] = "":(, IndexError('line number out of range',)) ->> BufferAttr -vim.current.buffer.xxx:(, AttributeError("'vim.buffer' object has no attribute 'xxx'",)) ->> BufferSetattr -vim.current.buffer.name = True:(, TypeError('expected bytes() or str() instance, but got bool',)) -vim.current.buffer.xxx = True:(, AttributeError('xxx',)) ->> BufferMark -vim.current.buffer.mark(0):(, TypeError('expected bytes() or str() instance, but got int',)) -vim.current.buffer.mark("abcM"):(, ValueError('mark name must be a single character',)) -vim.current.buffer.mark("!"):(, error('invalid mark name',)) ->> BufferRange -vim.current.buffer.range(1, 2, 3):(, TypeError('function takes exactly 2 arguments (3 given)',)) -> BufMap ->> BufMapItem -vim.buffers[100000000]:(, KeyError(100000000,)) ->>> Testing NumberToLong using vim.buffers[%s] -vim.buffers[[]]:(, TypeError('expected int() or something supporting coercing to int(), but got list',)) -vim.buffers[None]:(, TypeError('expected int() or something supporting coercing to int(), but got NoneType',)) -vim.buffers[-1]:(, ValueError('number must be greater than zero',)) -vim.buffers[0]:(, ValueError('number must be greater than zero',)) -<<< Finished -> Current ->> CurrentGetattr -vim.current.xxx:(, AttributeError("'vim.currentdata' object has no attribute 'xxx'",)) ->> CurrentSetattr -vim.current.line = True:(, TypeError('bad argument type for built-in operation',)) -vim.current.buffer = True:(, TypeError('expected vim.Buffer object, but got bool',)) -vim.current.window = True:(, TypeError('expected vim.Window object, but got bool',)) -vim.current.tabpage = True:(, TypeError('expected vim.TabPage object, but got bool',)) -vim.current.xxx = True:(, AttributeError('xxx',)) -['.'] -'.' -3,xx -before -after -pythonx/topmodule/__init__.py -pythonx/topmodule/submodule/__init__.py -pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py -vim.command("throw 'abcN'"):(, error('abcN',)) -Exe("throw 'def'"):(, error('def',)) -vim.eval("Exe('throw ''ghi''')"):(, error('ghi',)) -vim.eval("Exe('echoerr ''jkl''')"):(, error('Vim(echoerr):jkl',)) -vim.eval("Exe('xxx_non_existent_command_xxx')"):(, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)) -vim.eval("xxx_unknown_function_xxx()"):(, error('Vim:E117: Unknown function: xxx_unknown_function_xxx',)) -vim.bindeval("Exe('xxx_non_existent_command_xxx')"):(, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)) -Caught KeyboardInterrupt -Running :put -No exception - diff --git a/src/testdir/test_arglist.vim b/src/testdir/test_arglist.vim index f9995a4bc8..198ca989a0 100644 --- a/src/testdir/test_arglist.vim +++ b/src/testdir/test_arglist.vim @@ -175,22 +175,25 @@ func Test_argument() let save_columns = &columns let &columns = 79 - exe 'args ' .. join(range(1, 81)) - call assert_equal(join([ - \ '', - \ '[1] 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 ', - \ '2 7 12 17 22 27 32 37 42 47 52 57 62 67 72 77 ', - \ '3 8 13 18 23 28 33 38 43 48 53 58 63 68 73 78 ', - \ '4 9 14 19 24 29 34 39 44 49 54 59 64 69 74 79 ', - \ '5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 ', - \ ], "\n"), - \ execute('args')) + try + exe 'args ' .. join(range(1, 81)) + call assert_equal(join([ + \ '', + \ '[1] 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 ', + \ '2 7 12 17 22 27 32 37 42 47 52 57 62 67 72 77 ', + \ '3 8 13 18 23 28 33 38 43 48 53 58 63 68 73 78 ', + \ '4 9 14 19 24 29 34 39 44 49 54 59 64 69 74 79 ', + \ '5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 ', + \ ], "\n"), + \ execute('args')) - " No trailing newline with one item per row. - let long_arg = repeat('X', 81) - exe 'args ' .. long_arg - call assert_equal("\n[".long_arg.']', execute('args')) - let &columns = save_columns + " No trailing newline with one item per row. + let long_arg = repeat('X', 81) + exe 'args ' .. long_arg + call assert_equal("\n[".long_arg.']', execute('args')) + finally + let &columns = save_columns + endtry " Setting argument list should fail when the current buffer has unsaved " changes diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 898c6c1e45..6164a2a599 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -2585,7 +2585,7 @@ func Test_autocmd_window() edit one.txt tabnew two.txt let g:blist = [] - augroup aucmd_win_test + augroup aucmd_win_test1 au! au BufEnter * call add(g:blist, [expand(''), \ win_gettype(bufwinnr(expand('')))]) @@ -2594,11 +2594,50 @@ func Test_autocmd_window() doautoall BufEnter call assert_equal([['one.txt', 'autocmd'], ['two.txt', '']], g:blist) + augroup aucmd_win_test1 + au! + augroup END + augroup! aucmd_win_test1 + %bw! +endfunc + +" Test for trying to close the temporary window used for executing an autocmd +func Test_close_autocmd_window() + %bw! + edit one.txt + tabnew two.txt + augroup aucmd_win_test2 + au! + au BufEnter * if expand('') == 'one.txt' | 1close | endif + augroup END + + call assert_fails('doautoall BufEnter', 'E813:') + + augroup aucmd_win_test2 + au! + augroup END + augroup! aucmd_win_test2 + %bwipe! +endfunc + +" Test for trying to close the tab that has the temporary window for exeucing +" an autocmd. +func Test_close_autocmd_tab() + edit one.txt + tabnew two.txt + augroup aucmd_win_test + au! + au BufEnter * if expand('') == 'one.txt' | tabfirst | tabonly | endif + augroup END + + call assert_fails('doautoall BufEnter', 'E813:') + + tabonly augroup aucmd_win_test au! augroup END augroup! aucmd_win_test - %bw! + %bwipe! endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim index de163538e4..5981e247ac 100644 --- a/src/testdir/test_buffer.vim +++ b/src/testdir/test_buffer.vim @@ -1,5 +1,7 @@ " Tests for Vim buffer +source check.vim + " Test for the :bunload command with an offset func Test_bunload_with_offset() %bwipe! @@ -152,6 +154,24 @@ func Test_bdelete_cmd() set nobuflisted enew call assert_fails('bdelete ' .. bnr, 'E516:') + + " Deleting more than one buffer + new Xbuf1 + new Xbuf2 + exe 'bdel ' .. bufnr('Xbuf2') .. ' ' .. bufnr('Xbuf1') + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xbuf1')[0].loaded) + call assert_equal(0, getbufinfo('Xbuf2')[0].loaded) + + " Deleting more than one buffer and an invalid buffer + new Xbuf1 + new Xbuf2 + let cmd = "exe 'bdel ' .. bufnr('Xbuf2') .. ' xxx ' .. bufnr('Xbuf1')" + call assert_fails(cmd, 'E94:') + call assert_equal(2, winnr('$')) + call assert_equal(1, getbufinfo('Xbuf1')[0].loaded) + call assert_equal(0, getbufinfo('Xbuf2')[0].loaded) + %bwipe! endfunc @@ -166,4 +186,188 @@ func Test_buffer_error() %bwipe endfunc +" Test for the status messages displayed when unloading, deleting or wiping +" out buffers +func Test_buffer_statusmsg() + CheckEnglish + set report=1 + new Xbuf1 + new Xbuf2 + let bnr = bufnr() + exe "normal 2\" + call assert_match('buf ' .. bnr .. ':', v:statusmsg) + bunload Xbuf1 Xbuf2 + call assert_equal('2 buffers unloaded', v:statusmsg) + bdel Xbuf1 Xbuf2 + call assert_equal('2 buffers deleted', v:statusmsg) + bwipe Xbuf1 Xbuf2 + call assert_equal('2 buffers wiped out', v:statusmsg) + set report& +endfunc + +" Test for quitting the 'swapfile exists' dialog with the split buffer +" command. +func Test_buffer_sbuf_cleanup() + call writefile([], 'Xfile') + " first open the file in a buffer + new Xfile + let bnr = bufnr() + close + " create the swap file + call writefile([], '.Xfile.swp') + " Remove the catch-all that runtest.vim adds + au! SwapExists + augroup BufTest + au! + autocmd SwapExists Xfile let v:swapchoice='q' + augroup END + exe 'sbuf ' . bnr + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xfile')[0].loaded) + + " test for :sball + sball + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xfile')[0].loaded) + + %bw! + set shortmess+=F + let v:statusmsg = '' + edit Xfile + call assert_equal('', v:statusmsg) + call assert_equal(1, winnr('$')) + call assert_equal(0, getbufinfo('Xfile')[0].loaded) + set shortmess& + + call delete('Xfile') + call delete('.Xfile.swp') + augroup BufTest + au! + augroup END + augroup! BufTest +endfunc + +" Test for deleting a modified buffer with :confirm +func Test_bdel_with_confirm() + CheckUnix + CheckNotGui + CheckFeature dialog_con + new + call setline(1, 'test') + call assert_fails('bdel', 'E89:') + call feedkeys('c', 'L') + confirm bdel + call assert_equal(2, winnr('$')) + call assert_equal(1, &modified) + call feedkeys('n', 'L') + confirm bdel + call assert_equal(1, winnr('$')) +endfunc + +" Test for editing another buffer from a modified buffer with :confirm +func Test_goto_buf_with_confirm() + CheckUnix + CheckNotGui + CheckFeature dialog_con + new Xfile + enew + call setline(1, 'test') + call assert_fails('b Xfile', 'E37:') + call feedkeys('c', 'L') + call assert_fails('confirm b Xfile', 'E37:') + call assert_equal(1, &modified) + call assert_equal('', @%) + call feedkeys('y', 'L') + call assert_fails('confirm b Xfile', 'E37:') + call assert_equal(1, &modified) + call assert_equal('', @%) + call feedkeys('n', 'L') + confirm b Xfile + call assert_equal('Xfile', @%) + close! +endfunc + +" Test for splitting buffer with 'switchbuf' +func Test_buffer_switchbuf() + new Xfile + wincmd w + set switchbuf=useopen + sbuf Xfile + call assert_equal(1, winnr()) + call assert_equal(2, winnr('$')) + set switchbuf=usetab + tabnew + sbuf Xfile + call assert_equal(1, tabpagenr()) + call assert_equal(2, tabpagenr('$')) + set switchbuf& + %bw +endfunc + +" Test for BufAdd autocommand wiping out the buffer +func Test_bufadd_autocmd_bwipe() + %bw! + augroup BufAdd_Wipe + au! + autocmd BufAdd Xfile %bw! + augroup END + edit Xfile + call assert_equal('', @%) + call assert_equal(0, bufexists('Xfile')) + augroup BufAdd_Wipe + au! + augroup END + augroup! BufAdd_Wipe +endfunc + +" Test for trying to load a buffer with text locked +" e in the command line is used to lock the text +func Test_load_buf_with_text_locked() + new Xfile1 + edit Xfile2 + let cmd = ":\eexecute(\"normal \\")\\" + call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') + %bw! +endfunc + +" Test for using CTRL-^ to edit the alternative file keeping the cursor +" position with 'nostartofline'. Also test using the 'buf' command. +func Test_buffer_edit_altfile() + call writefile(repeat(['one two'], 50), 'Xfile1') + call writefile(repeat(['five six'], 50), 'Xfile2') + set nosol + edit Xfile1 + call cursor(25, 5) + edit Xfile2 + call cursor(30, 4) + exe "normal \" + call assert_equal([0, 25, 5, 0], getpos('.')) + exe "normal \" + call assert_equal([0, 30, 4, 0], getpos('.')) + buf Xfile1 + call assert_equal([0, 25, 5, 0], getpos('.')) + buf Xfile2 + call assert_equal([0, 30, 4, 0], getpos('.')) + set sol& + call delete('Xfile1') + call delete('Xfile2') +endfunc + +" Test for running the :sball command with a maximum window count and a +" modified buffer +func Test_sball_with_count() + %bw! + edit Xfile1 + call setline(1, ['abc']) + new Xfile2 + new Xfile3 + new Xfile4 + 2sball + call assert_equal(bufnr('Xfile4'), winbufnr(1)) + call assert_equal(bufnr('Xfile1'), winbufnr(2)) + call assert_equal(0, getbufinfo('Xfile2')[0].loaded) + call assert_equal(0, getbufinfo('Xfile3')[0].loaded) + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 5d772eacdc..eb213f1976 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -191,6 +191,10 @@ func Test_highlight_completion() call assert_equal('"hi default', getreg(':')) call feedkeys(":hi c\\\"\", 'xt') call assert_equal('"hi clear', getreg(':')) + call feedkeys(":hi clear Aardig Aard\\\"\", 'xt') + call assert_equal('"hi clear Aardig Aardig', getreg(':')) + call feedkeys(":hi Aardig \\\"\", 'xt') + call assert_equal("\"hi Aardig \t", getreg(':')) " A cleared group does not show up in completions. hi Anders ctermfg=green @@ -201,6 +205,14 @@ func Test_highlight_completion() call assert_equal([], getcompletion('A', 'highlight')) endfunc +" Test for command-line expansion of "hi Ni " (easter egg) +func Test_highlight_easter_egg() + call test_override('ui_delay', 1) + call feedkeys(":hi Ni \\\"\", 'xt') + call assert_equal("\"hi Ni \", @:) + call test_override('ALL', 0) +endfunc + func Test_getcompletion() if !has('cmdline_compl') return @@ -392,6 +404,7 @@ func Test_getcompletion() call delete('Xtags') set tags& + call assert_fails("call getcompletion('\\\\@!\\\\@=', 'buffer')", 'E871:') call assert_fails('call getcompletion("", "burp")', 'E475:') call assert_fails('call getcompletion("abc", [])', 'E475:') endfunc @@ -1580,8 +1593,11 @@ func Test_read_shellcmd() call feedkeys(":r! ++enc=utf-8 r\\\"\", 'tx') call assert_notmatch('^"r!.*\', @:) call assert_match('^"r!.*\', @:) + + call feedkeys(":r ++enc=utf-8 !rm\\\"\", 'tx') + call assert_notmatch('^"r.*\', @:) + call assert_match('^"r ++enc\S\+ !.*\', @:) endif endfunc - " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_comments.vim b/src/testdir/test_comments.vim new file mode 100644 index 0000000000..c34b85c42d --- /dev/null +++ b/src/testdir/test_comments.vim @@ -0,0 +1,277 @@ +" Tests for the various flags in the 'comments' option + +" Test for the 'n' flag in 'comments' +func Test_comment_nested() + new + setlocal comments=n:> fo+=ro + exe "normal i> B\nD\ggOA\joC\Go\>>> F\nH" + exe "normal 5GOE\6GoG" + let expected =<< trim END + > A + > B + > C + > D + >>>> E + >>>> F + >>>> G + >>>> H + END + call assert_equal(expected, getline(1, '$')) + close! +endfunc + +" Test for the 'b' flag in 'comments' +func Test_comment_blank() + new + setlocal comments=b:* fo+=ro + exe "normal i* E\nF\n\G\nH\ggOC\O\B\OA\2joD" + let expected =<< trim END + A + *B + * C + * D + * E + * F + *G + H + END + call assert_equal(expected, getline(1, '$')) + close! +endfunc + +" Test for the 'f' flag in 'comments' (only the first line has a comment +" string) +func Test_comment_firstline() + new + setlocal comments=f:- fo+=ro + exe "normal i- B\nD\ggoC\ggOA\" + call assert_equal(['A', '- B', ' C', ' D'], getline(1, '$')) + %d + setlocal comments=:- + exe "normal i- B\nD\ggoC\ggOA\" + call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$')) + close! +endfunc + +" Test for the 's', 'm' and 'e' flags in 'comments' +" Test for automatically adding comment leaders in insert mode +func Test_comment_threepiece() + new + setlocal expandtab + call setline(1, ["\t/*"]) + setlocal formatoptions=croql + call cursor(1, 3) + call feedkeys("A\\/", 'tnix') + call assert_equal(["\t/*", " *", " */"], getline(1, '$')) + + " If a comment ends in a single line, then don't add it in the next line + %d + call setline(1, '/* line1 */') + call feedkeys("A\next line", 'xt') + call assert_equal(['/* line1 */', 'next line'], getline(1, '$')) + + %d + " Copy the trailing indentation from the leader comment to a new line + setlocal autoindent noexpandtab + call feedkeys("a\t/*\tone\ntwo\n/", 'xt') + call assert_equal(["\t/*\tone", "\t *\ttwo", "\t */"], getline(1, '$')) + close! +endfunc + +" Test for the 'r' flag in 'comments' (right align comment) +func Test_comment_rightalign() + new + setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro + exe "normal i=\o\t /***\nD\n/" + exe "normal 2GOA\joB\jOC\joE\GOF\joG" + let expected =<< trim END + = + A + /*** + ** B + ** C + ** D + ** E + ** F + ******/ + G + END + call assert_equal(expected, getline(1, '$')) + close! +endfunc + +" Test for the 'O' flag in 'comments' +func Test_comment_O() + new + setlocal comments=Ob:* fo+=ro + exe "normal i* B\nD\kOA\joC" + let expected =<< trim END + A + * B + * C + * D + END + call assert_equal(expected, getline(1, '$')) + close! +endfunc + +" Test for using a multibyte character as a comment leader +func Test_comment_multibyte_leader() + new + let t =<< trim END + { + X + Xa + XaY + XY + XYZ + X Y + X YZ + XX + XXa + XXY + } + END + call setline(1, t) + call cursor(2, 1) + + set tw=2 fo=cqm comments=n:X + exe "normal gqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgq" + let t =<< trim END + X + Xa + XaY + XY + XYZ + X Y + X YZ + XX + XXa + XXY + END + exe "normal o\n" . join(t, "\n") + + let expected =<< trim END + { + X + Xa + Xa + XY + XY + XY + XZ + X Y + X Y + X Z + XX + XXa + XXY + + X + Xa + Xa + XY + XY + XY + XZ + X Y + X Y + X Z + XX + XXa + XXY + } + END + call assert_equal(expected, getline(1, '$')) + + set tw& fo& comments& + close! +endfunc + +" Test for a space character in 'comments' setting +func Test_comment_space() + new + setlocal comments=b:\ > fo+=ro + exe "normal i> B\nD\ggOA\joC" + exe "normal Go > F\nH\kOE\joG" + let expected =<< trim END + A + > B + C + D + > E + > F + > G + > H + END + call assert_equal(expected, getline(1, '$')) + close! +endfunc + +" Test for formatting lines with and without comments +func Test_comment_format_lines() + new + call setline(1, ['one', '/* two */', 'three']) + normal gggqG + call assert_equal(['one', '/* two */', 'three'], getline(1, '$')) + close! +endfunc + +" Test for using 'a' in 'formatoptions' with comments +func Test_comment_autoformat() + new + setlocal formatoptions+=a + call feedkeys("a- one\n- two\n", 'xt') + call assert_equal(['- one', '- two', ''], getline(1, '$')) + + %d + call feedkeys("a\none\n", 'xt') + call assert_equal(['', 'one', ''], getline(1, '$')) + + setlocal formatoptions+=aw + %d + call feedkeys("aone \ntwo\n", 'xt') + call assert_equal(['one two', ''], getline(1, '$')) + + %d + call feedkeys("aone\ntwo\n", 'xt') + call assert_equal(['one', 'two', ''], getline(1, '$')) + + close! +endfunc + +" Test for joining lines with comments ('j' flag in 'formatoptions') +func Test_comment_join_lines_fo_j() + new + setlocal fo+=j comments=:// + call setline(1, ['i++; // comment1', ' // comment2']) + normal J + call assert_equal('i++; // comment1 comment2', getline(1)) + setlocal fo-=j + call setline(1, ['i++; // comment1', ' // comment2']) + normal J + call assert_equal('i++; // comment1 // comment2', getline(1)) + " Test with nested comments + setlocal fo+=j comments=n:>,n:) + call setline(1, ['i++; > ) > ) comment1', ' > ) comment2']) + normal J + call assert_equal('i++; > ) > ) comment1 comment2', getline(1)) + close! +endfunc + +" Test for formatting lines where only the first line has a comment. +func Test_comment_format_firstline_comment() + new + setlocal formatoptions=tcq + call setline(1, ['- one two', 'three']) + normal gggqG + call assert_equal(['- one two three'], getline(1, '$')) + + %d + call setline(1, ['- one', '- two']) + normal gggqG + call assert_equal(['- one', '- two'], getline(1, '$')) + close! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_conceal.vim b/src/testdir/test_conceal.vim index bf942b7880..b555682d2d 100644 --- a/src/testdir/test_conceal.vim +++ b/src/testdir/test_conceal.vim @@ -254,4 +254,26 @@ func Test_conceal_cursor_pos() call delete('XTest_conceal_curpos') endfunc +func Test_conceal_eol() + new! + setlocal concealcursor=n conceallevel=1 + call setline(1, ["x", ""]) + call matchaddpos('Conceal', [[2, 1, 1]], 2, -1, {'conceal': 1}) + redraw! + + call assert_notequal(screenchar(1, 1), screenchar(2, 2)) + call assert_equal(screenattr(1, 1), screenattr(1, 2)) + call assert_equal(screenattr(1, 2), screenattr(2, 2)) + call assert_equal(screenattr(2, 1), screenattr(2, 2)) + + set list + redraw! + + call assert_equal(screenattr(1, 1), screenattr(2, 2)) + call assert_notequal(screenattr(1, 1), screenattr(1, 2)) + call assert_notequal(screenattr(1, 2), screenattr(2, 1)) + + set nolist +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_cscope.vim b/src/testdir/test_cscope.vim index a1a839fcd2..9d12e2f602 100644 --- a/src/testdir/test_cscope.vim +++ b/src/testdir/test_cscope.vim @@ -103,7 +103,7 @@ func Test_cscopeWithCscopeConnections() for cmd in ['cs find f Xmemfile_test.c', 'cs find 7 Xmemfile_test.c'] enew let a = execute(cmd) - call assert_true(a =~ '"Xmemfile_test.c" \d\+L, \d\+C') + call assert_true(a =~ '"Xmemfile_test.c" \d\+L, \d\+B') call assert_equal('Xmemfile_test.c', @%) endfor @@ -113,7 +113,7 @@ func Test_cscopeWithCscopeConnections() let a = execute(cmd) let alines = split(a, '\n', 1) call assert_equal('', alines[0]) - call assert_true(alines[1] =~ '"Xmemfile_test.c" \d\+L, \d\+C') + call assert_true(alines[1] =~ '"Xmemfile_test.c" \d\+L, \d\+B') call assert_equal('(1 of 1): <> #include ', alines[2]) call assert_equal('#include ', getline('.')) endfor diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim index 4544834b9d..a3f6d5867b 100644 --- a/src/testdir/test_diffmode.vim +++ b/src/testdir/test_diffmode.vim @@ -1118,4 +1118,16 @@ func Test_diff_rnu() call delete('Xtest_diff_rnu') endfunc +func Test_diff_multilineconceal() + new + diffthis + + new + call matchadd('Conceal', 'a\nb', 9, -1, {'conceal': 'Y'}) + set cole=2 cocu=n + call setline(1, ["a", "b"]) + diffthis + redraw +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim index 868ac6fc40..2c693e21d4 100644 --- a/src/testdir/test_excmd.vim +++ b/src/testdir/test_excmd.vim @@ -189,49 +189,58 @@ func Test_confirm_cmd() CheckNotGui CheckRunVimInTerminal - call writefile(['foo1'], 'foo') - call writefile(['bar1'], 'bar') + call writefile(['foo1'], 'Xfoo') + call writefile(['bar1'], 'Xbar') " Test for saving all the modified buffers - let buf = RunVimInTerminal('', {'rows': 20}) - call term_sendkeys(buf, ":set nomore\n") - call term_sendkeys(buf, ":new foo\n") - call term_sendkeys(buf, ":call setline(1, 'foo2')\n") - call term_sendkeys(buf, ":new bar\n") - call term_sendkeys(buf, ":call setline(1, 'bar2')\n") - call term_sendkeys(buf, ":wincmd b\n") + let lines =<< trim END + set nomore + new Xfoo + call setline(1, 'foo2') + new Xbar + call setline(1, 'bar2') + wincmd b + END + call writefile(lines, 'Xscript') + let buf = RunVimInTerminal('-S Xscript', {'rows': 20}) call term_sendkeys(buf, ":confirm qall\n") call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000) call term_sendkeys(buf, "A") call StopVimInTerminal(buf) - call assert_equal(['foo2'], readfile('foo')) - call assert_equal(['bar2'], readfile('bar')) + call assert_equal(['foo2'], readfile('Xfoo')) + call assert_equal(['bar2'], readfile('Xbar')) " Test for discarding all the changes to modified buffers - let buf = RunVimInTerminal('', {'rows': 20}) - call term_sendkeys(buf, ":set nomore\n") - call term_sendkeys(buf, ":new foo\n") - call term_sendkeys(buf, ":call setline(1, 'foo3')\n") - call term_sendkeys(buf, ":new bar\n") - call term_sendkeys(buf, ":call setline(1, 'bar3')\n") - call term_sendkeys(buf, ":wincmd b\n") + let lines =<< trim END + set nomore + new Xfoo + call setline(1, 'foo3') + new Xbar + call setline(1, 'bar3') + wincmd b + END + call writefile(lines, 'Xscript') + let buf = RunVimInTerminal('-S Xscript', {'rows': 20}) call term_sendkeys(buf, ":confirm qall\n") call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000) call term_sendkeys(buf, "D") call StopVimInTerminal(buf) - call assert_equal(['foo2'], readfile('foo')) - call assert_equal(['bar2'], readfile('bar')) + call assert_equal(['foo2'], readfile('Xfoo')) + call assert_equal(['bar2'], readfile('Xbar')) " Test for saving and discarding changes to some buffers - let buf = RunVimInTerminal('', {'rows': 20}) - call term_sendkeys(buf, ":set nomore\n") - call term_sendkeys(buf, ":new foo\n") - call term_sendkeys(buf, ":call setline(1, 'foo4')\n") - call term_sendkeys(buf, ":new bar\n") - call term_sendkeys(buf, ":call setline(1, 'bar4')\n") - call term_sendkeys(buf, ":wincmd b\n") + let lines =<< trim END + set nomore + new Xfoo + call setline(1, 'foo4') + new Xbar + call setline(1, 'bar4') + wincmd b + END + call writefile(lines, 'Xscript') + let buf = RunVimInTerminal('-S Xscript', {'rows': 20}) call term_sendkeys(buf, ":confirm qall\n") call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000) call term_sendkeys(buf, "N") @@ -239,11 +248,12 @@ func Test_confirm_cmd() call term_sendkeys(buf, "Y") call StopVimInTerminal(buf) - call assert_equal(['foo4'], readfile('foo')) - call assert_equal(['bar2'], readfile('bar')) + call assert_equal(['foo4'], readfile('Xfoo')) + call assert_equal(['bar2'], readfile('Xbar')) - call delete('foo') - call delete('bar') + call delete('Xscript') + call delete('Xfoo') + call delete('Xbar') endfunc func Test_confirm_cmd_cancel() @@ -251,10 +261,13 @@ func Test_confirm_cmd_cancel() CheckRunVimInTerminal " Test for closing a window with a modified buffer - let buf = RunVimInTerminal('', {'rows': 20}) - call term_sendkeys(buf, ":set nomore\n") - call term_sendkeys(buf, ":new\n") - call term_sendkeys(buf, ":call setline(1, 'abc')\n") + let lines =<< trim END + set nomore + new + call setline(1, 'abc') + END + call writefile(lines, 'Xscript') + let buf = RunVimInTerminal('-S Xscript', {'rows': 20}) call term_sendkeys(buf, ":confirm close\n") call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$', \ term_getline(buf, 20))}, 1000) @@ -267,6 +280,43 @@ func Test_confirm_cmd_cancel() call WaitForAssert({-> assert_match('^ *0,0-1 All$', \ term_getline(buf, 20))}, 1000) call StopVimInTerminal(buf) + call delete('Xscript') +endfunc + +" The ":confirm" prompt was sometimes used with the terminal in cooked mode. +" This test verifies that a "\" character is NOT required to respond to a +" prompt from the ":conf q" and ":conf wq" commands. +func Test_confirm_q_wq() + CheckNotGui + CheckRunVimInTerminal + + call writefile(['foo'], 'Xfoo') + + let lines =<< trim END + set hidden nomore + call setline(1, 'abc') + edit Xfoo + END + call writefile(lines, 'Xscript') + let buf = RunVimInTerminal('-S Xscript', {'rows': 20}) + call term_sendkeys(buf, ":confirm q\n") + call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$', + \ term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, 'C') + call WaitForAssert({-> assert_notmatch('^\[Y\]es, (N)o, (C)ancel: C*$', + \ term_getline(buf, 20))}, 1000) + + call term_sendkeys(buf, ":edit Xfoo\n") + call term_sendkeys(buf, ":confirm wq\n") + call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$', + \ term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, 'C') + call WaitForAssert({-> assert_notmatch('^\[Y\]es, (N)o, (C)ancel: C*$', + \ term_getline(buf, 20))}, 1000) + call StopVimInTerminal(buf) + + call delete('Xscript') + call delete('Xfoo') endfunc " Test for the :print command @@ -371,6 +421,11 @@ func Test_run_excmd_with_text_locked() close call assert_fails("call feedkeys(\":\=execute('bnext')\\", 'xt')", 'E565:') + + " :tabfirst + tabnew + call assert_fails("call feedkeys(\":\=execute('tabfirst')\\", 'xt')", 'E565:') + tabclose endfunc " Test for the :verbose command diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index ec73aeaae4..c5dd1f37c7 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -110,6 +110,13 @@ func Test_special_char() call assert_fails('echo "\') endfunc +func Test_method_with_prefix() + call assert_equal(1, !range(5)->empty()) + call assert_equal([0, 1, 2], --3->range()) + call assert_equal(0, !-3) + call assert_equal(1, !+-+0) +endfunc + func Test_option_value() " boolean set bri diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 6d245ae12f..8ec8355c24 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -139,7 +139,7 @@ let s:filename_checks = { \ 'dnsmasq': ['/etc/dnsmasq.conf'], \ 'dockerfile': ['Containerfile', 'Dockerfile', 'file.Dockerfile'], \ 'dosbatch': ['file.bat', 'file.sys'], - \ 'dosini': ['.editorconfig', '/etc/yum.conf', 'file.ini'], + \ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini'], \ 'dot': ['file.dot', 'file.gv'], \ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe'], \ 'dsl': ['file.dsl'], @@ -150,7 +150,7 @@ let s:filename_checks = { \ 'dylanlid': ['file.lid'], \ 'ecd': ['file.ecd'], \ 'edif': ['file.edf', 'file.edif', 'file.edo'], - \ 'elinks': ['/etc/elinks.conf', '/.elinks/elinks.conf'], + \ 'elinks': ['elinks.conf'], \ 'elm': ['file.elm'], \ 'elmfilt': ['filter-rules'], \ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'], @@ -665,4 +665,22 @@ func Test_filetype_indent_off() close endfunc +func Test_hook_file() + filetype on + + call writefile(['[Trigger]', 'this is pacman config'], 'Xfile.hook') + split Xfile.hook + call assert_equal('dosini', &filetype) + bwipe! + + call writefile(['not pacman'], 'Xfile.hook') + split Xfile.hook + call assert_notequal('dosini', &filetype) + bwipe! + + call delete('Xfile.hook') + filetype off +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_filter_cmd.vim b/src/testdir/test_filter_cmd.vim index de9a5d9046..278e7e4b6f 100644 --- a/src/testdir/test_filter_cmd.vim +++ b/src/testdir/test_filter_cmd.vim @@ -146,6 +146,11 @@ func Test_filter_commands() let res = split(execute("filter /\.c$/ marks"), "\n")[1:] call assert_equal([" A 1 0 file.c"], res) + " Test filtering :highlight command + highlight MyHlGroup ctermfg=10 + let res = split(execute("filter /MyHlGroup/ highlight"), "\n") + call assert_equal(["MyHlGroup xxx ctermfg=10"], res) + call setline(1, ['one', 'two', 'three']) 1mark a 2mark b diff --git a/src/testdir/test_gf.vim b/src/testdir/test_gf.vim index 3fa85113f1..eaa8c0fc95 100644 --- a/src/testdir/test_gf.vim +++ b/src/testdir/test_gf.vim @@ -74,11 +74,18 @@ func Test_gF() call assert_equal('Xfile', bufname('%')) call assert_equal(2, getcurpos()[1]) + " jumping to the file/line with CTRL-W_F + %bw! + edit Xfile1 + call setline(1, ['one', 'Xfile:4', 'three']) + exe "normal 2G\F" + call assert_equal('Xfile', bufname('%')) + call assert_equal(4, getcurpos()[1]) + set isfname& call delete('Xfile') call delete('Xfile2') - bwipe Xfile - bwipe Xfile2 + %bw! endfunc " Test for invoking 'gf' on a ${VAR} variable diff --git a/src/testdir/test_highlight.vim b/src/testdir/test_highlight.vim index 73b72289e6..3f84c12e69 100644 --- a/src/testdir/test_highlight.vim +++ b/src/testdir/test_highlight.vim @@ -701,8 +701,9 @@ endfunc func Test_highlight_cmd_errors() if has('gui_running') " This test doesn't fail in the MS-Windows console version. - call assert_fails('hi Xcomment ctermfg=fg', 'E419:') + call assert_fails('hi Xcomment ctermbg=fg', 'E419:') call assert_fails('hi Xcomment ctermfg=bg', 'E420:') + call assert_fails('hi Xcomment ctermfg=ul', 'E453:') endif " Try using a very long terminal code. Define a dummy terminal code for this @@ -713,4 +714,94 @@ func Test_highlight_cmd_errors() let &t_fo = "" endfunc +" Test for 'highlight' option +func Test_highlight_opt() + let save_hl = &highlight + call assert_fails('set highlight=j:b', 'E474:') + set highlight=f\ r + call assert_equal('f r', &highlight) + set highlight=fb + call assert_equal('fb', &highlight) + set highlight=fi + call assert_equal('fi', &highlight) + set highlight=f- + call assert_equal('f-', &highlight) + set highlight=fr + call assert_equal('fr', &highlight) + set highlight=fs + call assert_equal('fs', &highlight) + set highlight=fu + call assert_equal('fu', &highlight) + set highlight=fc + call assert_equal('fc', &highlight) + set highlight=ft + call assert_equal('ft', &highlight) + call assert_fails('set highlight=fr:Search', 'E474:') + set highlight=f:$# + call assert_match('W18:', v:statusmsg) + let &highlight = save_hl +endfunc + +" Test for User group highlighting used in the statusline +func Test_highlight_User() + CheckNotGui + hi User1 ctermfg=12 + redraw! + call assert_equal('12', synIDattr(synIDtrans(hlID('User1')), 'fg')) + hi clear +endfunc + +" Test for using RGB color values in a highlight group +func Test_highlight_RGB_color() + CheckGui + hi MySearch guifg=#110000 guibg=#001100 guisp=#000011 + call assert_equal('#110000', synIDattr(synIDtrans(hlID('MySearch')), 'fg#')) + call assert_equal('#001100', synIDattr(synIDtrans(hlID('MySearch')), 'bg#')) + call assert_equal('#000011', synIDattr(synIDtrans(hlID('MySearch')), 'sp#')) + hi clear +endfunc + +" Test for using default highlighting group +func Test_highlight_default() + highlight MySearch ctermfg=7 + highlight default MySearch ctermfg=5 + let hlSearch = HighlightArgs('MySearch') + call assert_match('ctermfg=7', hlSearch) + + highlight default QFName ctermfg=3 + call assert_match('ctermfg=3', HighlightArgs('QFName')) + hi clear +endfunc + +" Test for 'ctermul in a highlight group +func Test_highlight_ctermul() + CheckNotGui + call assert_notmatch('ctermul=', HighlightArgs('Normal')) + highlight Normal ctermul=3 + call assert_match('ctermul=3', HighlightArgs('Normal')) + highlight Normal ctermul=NONE +endfunc + +" Test for specifying 'start' and 'stop' in a highlight group +func Test_highlight_start_stop() + hi HlGrp1 start=[27h;[r; + call assert_match("start=^[[27h;^[[ r;", HighlightArgs('HlGrp1')) + hi HlGrp1 start=NONE + call assert_notmatch("start=", HighlightArgs('HlGrp1')) + hi HlGrp2 stop=[27h;[r; + call assert_match("stop=^[[27h;^[[ r;", HighlightArgs('HlGrp2')) + hi HlGrp2 stop=NONE + call assert_notmatch("stop=", HighlightArgs('HlGrp2')) + hi clear +endfunc + +" Test for setting various 'term' attributes +func Test_highlight_term_attr() + hi HlGrp3 term=bold,underline,undercurl,strikethrough,reverse,italic,standout + call assert_equal('hi HlGrp3 term=bold,standout,underline,undercurl,italic,reverse,strikethrough', HighlightArgs('HlGrp3')) + hi HlGrp3 term=NONE + call assert_equal('hi HlGrp3 cleared', HighlightArgs('HlGrp3')) + hi clear +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_iminsert.vim b/src/testdir/test_iminsert.vim index 04c8a15995..80088c3c07 100644 --- a/src/testdir/test_iminsert.vim +++ b/src/testdir/test_iminsert.vim @@ -27,7 +27,7 @@ func Test_iminsert2() set imactivatefunc= set imstatusfunc= - let expected = has('gui_running') ? 0 : 1 + let expected = (has('win32') && has('gui_running')) ? 0 : 1 call assert_equal(expected, s:imactivatefunc_called) call assert_equal(expected, s:imstatusfunc_called) endfunc @@ -38,10 +38,7 @@ func Test_getimstatus() elseif !has('gui_mac') CheckFeature xim endif - if has('gui_running') - if !has('win32') - throw 'Skipped: running in the GUI, only works on MS-Windows' - endif + if has('win32') && has('gui_running') set imactivatefunc= set imstatusfunc= else diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index b1af87ea9d..8a8d353289 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -709,6 +709,18 @@ func Test_reduce() call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E897:') call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E897:') call assert_fails("call reduce('', { acc, val -> acc + val }, 1)", 'E897:') + + let g:lut = [1, 2, 3, 4] + func EvilRemove() + call remove(g:lut, 1) + return 1 + endfunc + call assert_fails("call reduce(g:lut, { acc, val -> EvilRemove() }, 1)", 'E742:') + unlet g:lut + delfunc EvilRemove + + call assert_equal(42, reduce(test_null_list(), function('add'), 42)) + call assert_equal(42, reduce(test_null_blob(), function('add'), 42)) endfunc " splitting a string to a List using split() diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index bd50bce564..38ff87205c 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -4,6 +4,15 @@ source check.vim CheckFeature lua CheckFeature float +let s:luaver = split(split(luaeval('_VERSION'), ' ')[1], '\.') +let s:major = str2nr(s:luaver[0]) +let s:minor = str2nr(s:luaver[1]) +if s:major < 5 || (s:major == 5 && s:minor < 3) + let s:lua_53_or_later = 0 +else + let s:lua_53_or_later = 1 +endif + func TearDown() " Run garbage collection after each test to exercise luaV_setref(). call test_garbagecollect_now() @@ -28,6 +37,23 @@ func Test_lua_command() bwipe! endfunc +func Test_lua_luado() + new + call setline(1, ['one', 'two']) + luado return(linenr) + call assert_equal(['1', '2'], getline(1, '$')) + close! + + " Error cases + call assert_fails('luado string.format()', + \ "[string \"vim chunk\"]:1: bad argument #1 to 'format' (string expected, got no value)") + call assert_fails('luado func()', + \ s:lua_53_or_later + \ ? "[string \"vim chunk\"]:1: attempt to call a nil value (global 'func')" + \ : "[string \"vim chunk\"]:1: attempt to call global 'func' (a nil value)") + call assert_fails('luado error("failed")', "[string \"vim chunk\"]:1: failed") +endfunc + " Test vim.eval() func Test_lua_eval() " lua.eval with a number @@ -55,6 +81,24 @@ func Test_lua_eval() call assert_equal('blob', luaeval('vim.type(v)')) call assert_equal(0z00112233.deadbeef, luaeval('v')) + " lua.eval with a float + lua v = vim.eval('3.14') + call assert_equal('number', luaeval('vim.type(v)')) + call assert_equal(3.14, luaeval('v')) + + " lua.eval with a bool + lua v = vim.eval('v:true') + call assert_equal('number', luaeval('vim.type(v)')) + call assert_equal(1, luaeval('v')) + lua v = vim.eval('v:false') + call assert_equal('number', luaeval('vim.type(v)')) + call assert_equal(0, luaeval('v')) + + " lua.eval with a null + lua v = vim.eval('v:null') + call assert_equal('nil', luaeval('vim.type(v)')) + call assert_equal(v:null, luaeval('v')) + call assert_fails('lua v = vim.eval(nil)', \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got nil)") call assert_fails('lua v = vim.eval(true)', @@ -82,6 +126,13 @@ func Test_lua_window() " Window 3 does not exist so vim.window(3) should return nil call assert_equal('nil', luaeval('tostring(vim.window(3))')) + call assert_fails("let n = luaeval('vim.window().xyz()')", + \ s:lua_53_or_later + \ ? "[string \"luaeval\"]:1: attempt to call a nil value (field 'xyz')" + \ : "[string \"luaeval\"]:1: attempt to call field 'xyz' (a nil value)") + call assert_fails('lua vim.window().xyz = 1', + \ "[string \"vim chunk\"]:1: invalid window property: `xyz'") + %bwipe! endfunc @@ -125,6 +176,15 @@ endfunc func Test_lua_call() call assert_equal(has('lua'), luaeval('vim.call("has", "lua")')) call assert_equal(printf("Hello %s", "vim"), luaeval('vim.call("printf", "Hello %s", "vim")')) + + " Error cases + call assert_fails("call luaeval('vim.call(\"min\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)')", + \ '[string "luaeval"]:1: Function called with too many arguments') + lua co = coroutine.create(function () print("hi") end) + call assert_fails("call luaeval('vim.call(\"type\", co)')", + \ '[string "luaeval"]:1: lua: cannot convert value') + lua co = nil + call assert_fails("call luaeval('vim.call(\"abc\")')", '[string "luaeval"]:1: lua: call_vim_function failed') endfunc " Test vim.fn.* @@ -245,6 +305,15 @@ func Test_lua_buffer_insert() lua vim.buffer():insert('4', 10) call assert_equal(['1', '2', '3', '4'], getline(1, '$')) + call assert_equal('4', luaeval('vim.buffer()[4]')) + call assert_equal(v:null, luaeval('vim.buffer()[5]')) + call assert_equal(v:null, luaeval('vim.buffer()[{}]')) + call assert_fails('lua vim.buffer():xyz()', + \ s:lua_53_or_later + \ ? "[string \"vim chunk\"]:1: attempt to call a nil value (method 'xyz')" + \ : "[string \"vim chunk\"]:1: attempt to call method 'xyz' (a nil value)") + call assert_fails('lua vim.buffer()[1] = {}', + \ '[string "vim chunk"]:1: wrong argument to change') bwipe! endfunc @@ -252,6 +321,7 @@ endfunc func Test_lua_buffer_delete() new call setline(1, ['1', '2', '3']) + call cursor(3, 1) lua vim.buffer()[2] = nil call assert_equal(['1', '3'], getline(1, '$')) @@ -327,14 +397,30 @@ func Test_lua_list() call assert_equal(7, luaeval('#l')) call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)')) - lua l[0] = 124 - lua l[5] = nil + lua l[1] = 124 + lua l[6] = nil lua l:insert('first') lua l:insert('xx', 3) + call assert_fails('lua l:insert("xx", -20)', + \ '[string "vim chunk"]:1: invalid position') call assert_equal(['first', 124, 'abc', 'xx', v:true, v:false, v:null, {'a': 1, 'b': 2, 'c': 3}], l) lockvar 1 l call assert_fails('lua l:add("x")', '[string "vim chunk"]:1: list is locked') + call assert_fails('lua l:insert(2)', '[string "vim chunk"]:1: list is locked') + call assert_fails('lua l[9] = 1', '[string "vim chunk"]:1: list is locked') + + unlockvar l + let l = [1, 2] + lua ll = vim.eval('l') + let x = luaeval("ll[3]") + call assert_equal(v:null, x) + call assert_fails('let x = luaeval("ll:xyz(3)")', + \ s:lua_53_or_later + \ ? "[string \"luaeval\"]:1: attempt to call a nil value (method 'xyz')" + \ : "[string \"luaeval\"]:1: attempt to call method 'xyz' (a nil value)") + let y = luaeval("ll[{}]") + call assert_equal(v:null, y) lua l = nil endfunc @@ -353,6 +439,28 @@ func Test_lua_list_table() call assert_fails('lua vim.list(true)', '[string "vim chunk"]:1: table expected, got boolean') endfunc +func Test_lua_list_table_insert_remove() + if !s:lua_53_or_later + throw 'Skipped: Lua version < 5.3' + endif + + let l = [1, 2] + lua t = vim.eval('l') + lua table.insert(t, 10) + lua t[#t + 1] = 20 + lua table.insert(t, 2, 30) + call assert_equal(l, [1, 30, 2, 10, 20]) + lua table.remove(t, 2) + call assert_equal(l, [1, 2, 10, 20]) + lua t[3] = nil + call assert_equal(l, [1, 2, 20]) + lua removed_value = table.remove(t, 3) + call assert_equal(luaeval('removed_value'), 20) + lua t = nil + lua removed_value = nil + unlet l +endfunc + " Test l() i.e. iterator on list func Test_lua_list_iter() lua l = vim.list():add('foo'):add('bar') @@ -367,22 +475,22 @@ func Test_lua_recursive_list() lua l = vim.list():add(1):add(2) lua l = l:add(l) - call assert_equal(1, luaeval('l[0]')) - call assert_equal(2, luaeval('l[1]')) + call assert_equal(1, luaeval('l[1]')) + call assert_equal(2, luaeval('l[2]')) - call assert_equal(1, luaeval('l[2][0]')) - call assert_equal(2, luaeval('l[2][1]')) + call assert_equal(1, luaeval('l[3][1]')) + call assert_equal(2, luaeval('l[3][2]')) - call assert_equal(1, luaeval('l[2][2][0]')) - call assert_equal(2, luaeval('l[2][2][1]')) + call assert_equal(1, luaeval('l[3][3][1]')) + call assert_equal(2, luaeval('l[3][3][2]')) call assert_equal('[1, 2, [...]]', string(luaeval('l'))) call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)')) - call assert_equal(luaeval('tostring(l)'), luaeval('tostring(l[2])')) + call assert_equal(luaeval('tostring(l)'), luaeval('tostring(l[3])')) - call assert_equal(luaeval('l'), luaeval('l[2]')) - call assert_equal(luaeval('l'), luaeval('l[2][2]')) + call assert_equal(luaeval('l'), luaeval('l[3]')) + call assert_equal(luaeval('l'), luaeval('l[3][3]')) lua l = nil endfunc @@ -403,6 +511,7 @@ func Test_lua_dict() call assert_match('^dict: \%(0x\)\?\x\+$', luaeval('tostring(d)')) call assert_equal('abc', luaeval('d[1]')) + call assert_equal(v:null, luaeval('d[22]')) lua d[0] = 124 lua d[4] = nil @@ -410,6 +519,23 @@ func Test_lua_dict() lockvar 1 d call assert_fails('lua d[6] = 1', '[string "vim chunk"]:1: dict is locked') + unlockvar d + + " Error case + lua d = {} + lua d[''] = 10 + call assert_fails("let t = luaeval('vim.dict(d)')", + \ '[string "luaeval"]:1: table has empty key') + let d = {} + lua x = vim.eval('d') + call assert_fails("lua x[''] = 10", '[string "vim chunk"]:1: empty key') + lua x['a'] = nil + call assert_equal({}, d) + + " cannot assign funcrefs in the global scope + lua x = vim.eval('g:') + call assert_fails("lua x['min'] = vim.funcref('max')", + \ '[string "vim chunk"]:1: cannot assign funcref to builtin scope') lua d = nil endfunc @@ -467,6 +593,28 @@ func Test_lua_blob() call assert_fails('lua b:add(true)', '[string "vim chunk"]:1: string expected, got boolean') call assert_fails('lua b:add({})', '[string "vim chunk"]:1: string expected, got table') lua b = nil + + let b = 0z0102 + lua lb = vim.eval('b') + let n = luaeval('lb[1]') + call assert_equal(2, n) + let n = luaeval('lb[6]') + call assert_equal(v:null, n) + call assert_fails('let x = luaeval("lb:xyz(3)")', + \ s:lua_53_or_later + \ ? "[string \"luaeval\"]:1: attempt to call a nil value (method 'xyz')" + \ : "[string \"luaeval\"]:1: attempt to call method 'xyz' (a nil value)") + let y = luaeval("lb[{}]") + call assert_equal(v:null, y) + + lockvar b + call assert_fails('lua lb[1] = 2', '[string "vim chunk"]:1: blob is locked') + call assert_fails('lua lb:add("12")', '[string "vim chunk"]:1: blob is locked') + + " Error cases + lua t = {} + call assert_fails('lua b = vim.blob(t)', + \ '[string "vim chunk"]:1: string expected, got table') endfunc func Test_lua_funcref() @@ -480,6 +628,17 @@ func Test_lua_funcref() lua msg = vim.funcref"tr"(msg, "|", " ") call assert_equal("funcref test OK", luaeval('msg')) + " Error cases + call assert_fails('lua f1 = vim.funcref("")', + \ '[string "vim chunk"]:1: invalid function name: ') + call assert_fails('lua f1 = vim.funcref("10")', + \ '[string "vim chunk"]:1: invalid function name: 10') + let fname = test_null_string() + call assert_fails('lua f1 = vim.funcref(fname)', + \ "[string \"vim chunk\"]:1: bad argument #1 to 'funcref' (string expected, got nil)") + call assert_fails('lua vim.funcref("abc")()', + \ '[string "vim chunk"]:1: cannot call funcref') + " dict funcref function Mylen() dict return len(self.data) @@ -541,6 +700,35 @@ func Test_update_package_paths() call assert_equal("hello from lua", luaeval("require('testluaplugin').hello()")) endfunc +func Vim_func_call_lua_callback(Concat, Cb) + let l:message = a:Concat("hello", "vim") + call a:Cb(l:message) +endfunc + +func Test_pass_lua_callback_to_vim_from_lua() + lua pass_lua_callback_to_vim_from_lua_result = "" + call assert_equal("", luaeval("pass_lua_callback_to_vim_from_lua_result")) + lua <clearmatches() call assert_equal([], getmatches(winid)) + call assert_fails('echo getmatches(-1)', 'E957:') call setmatches(savematches, winid) call assert_equal(expect, savematches) @@ -281,6 +293,10 @@ func Test_matchaddpos_error() call assert_fails("call matchaddpos('Error', [{}])", 'E290:') call assert_equal(-1, matchaddpos('Error', test_null_list())) call assert_fails("call matchaddpos('Error', [1], [], 1)", 'E745:') + call assert_equal(-1, matchaddpos('Search', [[]])) + call assert_fails("call matchaddpos('Search', [[{}]])", 'E728:') + call assert_fails("call matchaddpos('Search', [[2, {}]])", 'E728:') + call assert_fails("call matchaddpos('Search', [[3, 4, {}]])", 'E728:') endfunc func OtherWindowCommon() @@ -333,4 +349,24 @@ func Test_matchadd_other_window() call delete('XscriptMatchCommon') endfunc +" Test for deleting matches outside of the screen redraw top/bottom lines +" This should cause a redraw of those lines. +func Test_matchdelete_redraw() + new + call setline(1, range(1, 500)) + call cursor(250, 1) + let m1 = matchaddpos('Search', [[250]]) + let m2 = matchaddpos('Search', [[10], [450]]) + redraw! + let m3 = matchaddpos('Search', [[240], [260]]) + call matchdelete(m2) + let m = getmatches() + call assert_equal(2, len(m)) + call assert_equal([250], m[0].pos1) + redraw! + call matchdelete(m1) + call assert_equal(1, len(getmatches())) + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_matchadd_conceal.vim b/src/testdir/test_matchadd_conceal.vim index be154643e6..6f6e21694c 100644 --- a/src/testdir/test_matchadd_conceal.vim +++ b/src/testdir/test_matchadd_conceal.vim @@ -63,9 +63,9 @@ func Test_matchadd_and_conceallevel_3() setlocal filetype=conf syntax on - 1put='# This is a Test' - " 1234567890123456 - let expect = '#ThisisaTest' + 1put='# This is a Test $' + " 1234567890123 + let expect = '#ThisisaTest$' call cursor(1, 1) call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'}) @@ -73,22 +73,25 @@ func Test_matchadd_and_conceallevel_3() let lnum = 2 call assert_equal(expect, Screenline(lnum)) call assert_equal(screenattr(lnum, 1), screenattr(lnum, 2)) - call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7)) - call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10)) - call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12)) + call assert_equal(screenattr(lnum, 1), screenattr(lnum, 7)) + call assert_equal(screenattr(lnum, 1), screenattr(lnum, 10)) + call assert_equal(screenattr(lnum, 1), screenattr(lnum, 12)) + call assert_equal(screenattr(lnum, 1), screenattr(lnum, 13)) + call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 14)) call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 16)) " more matchadd() - " 1234567890123456 - let expect = '#Thisisa Test' + " 12345678901234 + let expect = '#Thisisa Test$' call matchadd('ErrorMsg', '\%2l Test', 20, -1, {'conceal': 'X'}) redraw! call assert_equal(expect, Screenline(lnum)) call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 2)) - call assert_equal(screenattr(lnum, 2) , screenattr(lnum, 7)) + call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 7)) call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 10)) - call assert_equal(screenattr(lnum, 10), screenattr(lnum, 12)) + call assert_equal(screenattr(lnum, 10), screenattr(lnum, 13)) + call assert_equal(screenattr(lnum, 1), screenattr(lnum, 14)) call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 16)) call assert_notequal(screenattr(lnum, 10), screenattr(lnum, 16)) @@ -136,15 +139,18 @@ func Test_syn_and_match_conceal() new setlocal concealcursor=n conceallevel=1 - 1put='# This is a Test' - " 1234567890123456 - let expect = '#ZThisZisZaZTest' + 1put='# This is a Test ' - call cursor(1, 1) - call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'}) - syntax match MyConceal /\%2l / conceal containedin=ALL cchar=* - redraw! let lnum = 2 + call cursor(1, 1) + + " 123456789012345678 + let expect = '#ZThisZisZaZTestZZ' + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'}) + syntax match MyConceal /\%2l / conceal containedin=ALL + hi MyConceal ctermbg=4 ctermfg=2 + redraw! + call assert_equal(expect, Screenline(lnum)) call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2)) call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7)) @@ -152,8 +158,19 @@ func Test_syn_and_match_conceal() call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12)) call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) - " 1234567890123456 - let expect = '#*This*is*a*Test' + syntax clear MyConceal + syntax match MyConceal /\%2l / conceal containedin=ALL cchar=* + redraw! + + call assert_equal(expect, Screenline(lnum)) + call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12)) + call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) + + " 123456789012345678 + let expect = '#*This*is*a*Test**' call clearmatches() redraw! @@ -164,6 +181,48 @@ func Test_syn_and_match_conceal() call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12)) call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) + " 123456789012345678 + let expect = '#*ThisXis*a*Test**' + call matchadd('Conceal', '\%2l\%7c ', 10, -1, {'conceal': 'X'}) + redraw! + + call assert_equal(expect, Screenline(lnum)) + call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 7)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 10)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12)) + call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) + + " 123456789012345678 + let expect = '#*ThisXis*a*Test**' + call matchadd('ErrorMsg', '\%2l Test', 20, -1) + redraw! + + call assert_equal(expect, Screenline(lnum)) + call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12)) + call assert_notequal(screenattr(lnum, 12), screenattr(lnum, 13)) + call assert_equal(screenattr(lnum, 13), screenattr(lnum, 16)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 17)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 18)) + call assert_notequal(screenattr(lnum, 18), screenattr(lnum, 19)) + + " 123456789012345678 + let expect = '# ThisXis a Test' + syntax clear MyConceal + syntax match MyConceal /\%2l / conceal containedin=ALL + redraw! + + call assert_equal(expect, Screenline(lnum)) + call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 12)) + call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 12)) + call assert_notequal(screenattr(lnum, 12), screenattr(lnum, 13)) + call assert_equal(screenattr(lnum, 13), screenattr(lnum, 16)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 17)) + call assert_equal(screenattr(lnum, 2), screenattr(lnum, 18)) + call assert_notequal(screenattr(lnum, 18), screenattr(lnum, 19)) + syntax off quit! endfunc diff --git a/src/testdir/test_netbeans.vim b/src/testdir/test_netbeans.vim index 52c37820ef..8a35389d52 100644 --- a/src/testdir/test_netbeans.vim +++ b/src/testdir/test_netbeans.vim @@ -501,7 +501,7 @@ func Nb_basic(port) let l = readfile('Xnetbeans') call assert_equal('send: 3:insertDone!78 T F', l[-1]) sleep 1m - call assert_match('.*/Xfile4" 3L, 0C', v:statusmsg) + call assert_match('.*/Xfile4" 3L, 0B', v:statusmsg) let g:last += 3 " saveDone test @@ -511,7 +511,7 @@ func Nb_basic(port) let l = readfile('Xnetbeans') call assert_equal('send: 3:saveDone!79', l[-1]) sleep 1m - call assert_match('.*/Xfile4" 3L, 0C', v:statusmsg) + call assert_match('.*/Xfile4" 3L, 0B', v:statusmsg) let g:last += 3 " unimplemented command test diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index 2a06bb5b01..a4dc61945a 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -1267,6 +1267,7 @@ func Test_normal21_nv_hat() edit Xfoo | %bw call assert_fails(':buffer #', 'E86') call assert_fails(':execute "normal! \"', 'E23') + call assert_fails("normal i\#", 'E23:') " Test for the expected behavior when switching between two named buffers. edit Xfoo | edit Xbar diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index 7b7d9ddb58..d9905e3b94 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -956,4 +956,24 @@ func Test_window_opt() set window& endfunc +" Test for the 'winminheight' option +func Test_opt_winminheight() + only! + let &winheight = &lines + 4 + call assert_fails('let &winminheight = &lines + 2', 'E36:') + call assert_true(&winminheight <= &lines) + set winminheight& + set winheight& +endfunc + +" Test for the 'winminwidth' option +func Test_opt_winminwidth() + only! + let &winwidth = &columns + 4 + call assert_fails('let &winminwidth = &columns + 2', 'E36:') + call assert_true(&winminwidth <= &columns) + set winminwidth& + set winwidth& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 9fb51abd76..8631c71e7f 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -945,6 +945,8 @@ func Test_win_execute_not_allowed() call assert_fails('call win_execute(winid, "blast")', 'E994:') call assert_fails('call win_execute(winid, "edit")', 'E994:') call assert_fails('call win_execute(winid, "enew")', 'E994:') + call assert_fails('call win_execute(winid, "help")', 'E994:') + call assert_fails('call win_execute(winid, "1only")', 'E994:') call assert_fails('call win_execute(winid, "wincmd x")', 'E994:') call assert_fails('call win_execute(winid, "wincmd w")', 'E994:') call assert_fails('call win_execute(winid, "wincmd t")', 'E994:') diff --git a/src/testdir/test_python2.vim b/src/testdir/test_python2.vim index ae76fe6e89..f0b9b06c72 100644 --- a/src/testdir/test_python2.vim +++ b/src/testdir/test_python2.vim @@ -1,18 +1,68 @@ " Test for python 2 commands. -" TODO: move tests from test86.in here. source check.vim CheckFeature python +CheckFeature quickfix +source shared.vim + +" NOTE: This will cause errors when run under valgrind. +" This would require recompiling Python with: +" ./configure --without-pymalloc +" See http://svn.python.org/view/python/trunk/Misc/README.valgrind?view=markup +" + +" This function should be called first. This sets up python functions used by +" the other tests. +func Test_AAA_python_setup() + py << trim EOF + import vim + import sys + + def emsg(ei): + return ei[0].__name__ + ':' + repr(ei[1].args) + + def ee(expr, g=globals(), l=locals()): + try: + exec(expr, g, l) + except: + ei = sys.exc_info() + msg = emsg(ei) + msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'') + if expr.find('None') > -1: + msg = msg.replace('TypeError:(\'iteration over non-sequence\',)', + 'TypeError:("\'NoneType\' object is not iterable",)') + if expr.find('FailingNumber') > -1: + msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'') + msg = msg.replace('TypeError:(\'iteration over non-sequence\',)', + 'TypeError:("\'FailingNumber\' object is not iterable",)') + if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1: + msg = msg.replace('(\'', '("').replace('\',)', '",)') + # Some Python versions say can't, others cannot. + if msg.find('can\'t') > -1: + msg = msg.replace('can\'t', 'cannot') + # Some Python versions use single quote, some double quote + if msg.find('"cannot ') > -1: + msg = msg.replace('"cannot ', '\'cannot ') + if msg.find(' attributes"') > -1: + msg = msg.replace(' attributes"', ' attributes\'') + if expr == 'fd(self=[])': + # HACK: PyMapping_Check changed meaning + msg = msg.replace('AttributeError:(\'keys\',)', + 'TypeError:(\'unable to convert list to vim dictionary\',)') + vim.current.buffer.append(expr + ':' + msg) + else: + vim.current.buffer.append(expr + ':NOT FAILED') + EOF +endfunc func Test_pydo() - " Check deleting lines does not trigger ml_get error. - py import vim + " Check deleting lines does not trigger an ml_get error. new call setline(1, ['one', 'two', 'three']) pydo vim.command("%d_") bwipe! - " Check switching to another buffer does not trigger ml_get error. + " Check switching to another buffer does not trigger an ml_get error. new let wincount = winnr('$') call setline(1, ['one', 'two', 'three']) @@ -20,11 +70,23 @@ func Test_pydo() call assert_equal(wincount + 1, winnr('$')) bwipe! bwipe! + + " Try modifying a buffer with 'nomodifiable' set + set nomodifiable + call assert_fails('pydo toupper(line)', 'cannot save undo information') + set modifiable + + " Invalid command + call AssertException(['pydo non_existing_cmd'], + \ "Vim(pydo):NameError: global name 'non_existing_cmd' is not defined") + call AssertException(["pydo raise Exception('test')"], + \ 'Vim(pydo):Exception: test') + call AssertException(["pydo {lambda}"], + \ 'Vim(pydo):SyntaxError: invalid syntax') endfunc func Test_set_cursor() " Check that setting the cursor position works. - py import vim new call setline(1, ['first line', 'second line']) normal gg @@ -38,7 +100,6 @@ endfunc func Test_vim_function() " Check creating vim.Function object - py import vim func s:foo() return matchstr(expand(''), '\zs\d\+_foo$') @@ -59,6 +120,10 @@ func Test_vim_function() call assert_false(v:exception) endtry + " Non-existing function attribute + call AssertException(["let x = pyeval('f.abc')"], + \ 'Vim(let):AttributeError: abc') + py del f delfunc s:foo endfunc @@ -72,7 +137,6 @@ func Test_skipped_python_command_does_not_affect_pyxversion() endfunc func _SetUpHiddenBuffer() - py import vim new edit hidden setlocal bufhidden=hide @@ -122,7 +186,6 @@ func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_ClearLine() endfunc func _SetUpVisibleBuffer() - py import vim new let lnum = 0 while lnum < 10 @@ -149,7 +212,7 @@ func Test_Write_To_Current_Buffer_Fixes_Cursor_List() call assert_equal( line( '.' ), 1 ) bwipe! -endfunction +endfunc func Test_Write_To_Current_Buffer_Fixes_Cursor_Str() call _SetUpVisibleBuffer() @@ -158,7 +221,7 @@ func Test_Write_To_Current_Buffer_Fixes_Cursor_Str() call assert_equal( line( '.' ), 10 ) bwipe! -endfunction +endfunc func Test_Catch_Exception_Message() try @@ -188,4 +251,3502 @@ s+='B' call assert_equal('ABCDE', pyxeval('s')) endfunc +" Test for the buffer range object +func Test_python_range() + new + call setline(1, ['one', 'two', 'three']) + py b = vim.current.buffer + py r = b.range(1, 3) + call assert_equal(0, pyeval('r.start')) + call assert_equal(2, pyeval('r.end')) + call assert_equal('one', pyeval('r[0]')) + call assert_equal('one', pyeval('r[-3]')) + call assert_equal('three', pyeval('r[-4]')) + call assert_equal(['two', 'three'], pyeval('r[1:]')) + py r[0] = 'green' + call assert_equal(['green', 'two', 'three'], getline(1, '$')) + py r[0:2] = ['red', 'blue'] + call assert_equal(['red', 'blue', 'three'], getline(1, '$')) + call assert_equal(['start', 'end', '__members__'], pyeval('r.__members__')) + + " try different invalid start/end index for the range slice + %d + call setline(1, ['one', 'two', 'three']) + py r[-10:1] = ["a"] + py r[10:12] = ["b"] + py r[-10:-9] = ["c"] + py r[1:0] = ["d"] + call assert_equal(['c', 'd', 'a', 'two', 'three', 'b'], getline(1, '$')) + + " FIXME: The following code triggers ml_get errors + " %d + " let x = pyeval('r[:]') + + " Non-existing range attribute + call AssertException(["let x = pyeval('r.abc')"], + \ 'Vim(let):AttributeError: abc') + + close! +endfunc + +" Test for the python tabpage object +func Test_python_tabpage() + tabnew + py t = vim.tabpages[1] + py wl = t.windows + tabclose + " Accessing a closed tabpage + call AssertException(["let n = pyeval('t.number')"], + \ 'Vim(let):vim.error: attempt to refer to deleted tab page') + call AssertException(["let n = pyeval('len(wl)')"], + \ 'Vim(let):vim.error: attempt to refer to deleted tab page') + call AssertException(["py w = wl[0]"], + \ 'Vim(python):vim.error: attempt to refer to deleted tab page') + call AssertException(["py vim.current.tabpage = t"], + \ 'Vim(python):vim.error: attempt to refer to deleted tab page') + call assert_match(', , ]", substitute(pyeval('repr(dv)'),'0x\x\+','','g')) + call assert_equal("[('-1', ), ('0', -1L), ('1', 'asd'), ('b', ), ('f', )]", substitute(pyeval('repr(di)'),'0x\x\+','','g')) + call assert_equal(['0', '1', 'b', 'f', '-1'], keys(d)) + call assert_equal("[-1, 'asd', [1, 2, function('strlen')], function('1'), {'a': 1}]", string(values(d))) + py del dk + py del di + py del dv +endfunc + +func Test_python_list_del_items() + " removing items with del + let l = [0, function("strlen"), [1, 2, function("strlen"), {'a': 1}]] + py l = vim.bindeval('l') + py del l[2] + call assert_equal("[0, function('strlen')]", string(l)) + + let l = range(8) + py l = vim.bindeval('l') + py del l[:3] + py del l[1:] + call assert_equal([3], l) + + " removing items out of range: silently skip items that don't exist + + " The following two ranges delete nothing as they match empty list: + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[2:1] + call assert_equal([0, 1, 2, 3], l) + py del l[2:2] + call assert_equal([0, 1, 2, 3], l) + py del l[2:3] + call assert_equal([0, 1, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[2:4] + call assert_equal([0, 1], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[2:5] + call assert_equal([0, 1], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[2:6] + call assert_equal([0, 1], l) + + " The following two ranges delete nothing as they match empty list: + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[-1:2] + call assert_equal([0, 1, 2, 3], l) + py del l[-2:2] + call assert_equal([0, 1, 2, 3], l) + py del l[-3:2] + call assert_equal([0, 2, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[-4:2] + call assert_equal([2, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[-5:2] + call assert_equal([2, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[-6:2] + call assert_equal([2, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[::2] + call assert_equal([1, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[3:0:-2] + call assert_equal([0, 2], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py del l[2:4:-2] + let l = [0, 1, 2, 3] +endfunc + +func Test_python_dict_del_items() + let d = eval("{'0' : -1, '1' : 'asd', 'b' : [1, 2, function('strlen')], 'f' : function('min'), '-1' : {'a': 1}}") + py d = vim.bindeval('d') + py del d['-1'] + py del d['f'] + call assert_equal([1, 2, function('strlen')], pyeval('d.get(''b'', 1)')) + call assert_equal([1, 2, function('strlen')], pyeval('d.pop(''b'')')) + call assert_equal(1, pyeval('d.get(''b'', 1)')) + call assert_equal('asd', pyeval('d.pop(''1'', 2)')) + call assert_equal(2, pyeval('d.pop(''1'', 2)')) + call assert_equal('True', pyeval('repr(d.has_key(''0''))')) + call assert_equal('False', pyeval('repr(d.has_key(''1''))')) + call assert_equal('True', pyeval('repr(''0'' in d)')) + call assert_equal('False', pyeval('repr(''1'' in d)')) + call assert_equal("['0']", pyeval('repr(list(iter(d)))')) + call assert_equal({'0' : -1}, d) + call assert_equal("('0', -1L)", pyeval('repr(d.popitem())')) + call assert_equal('None', pyeval('repr(d.get(''0''))')) + call assert_equal('[]', pyeval('repr(list(iter(d)))')) +endfunc + +" Slice assignment to a list +func Test_python_slice_assignment() + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py l[0:0] = ['a'] + call assert_equal(['a', 0, 1, 2, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py l[1:2] = ['b'] + call assert_equal([0, 'b', 2, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py l[2:4] = ['c'] + call assert_equal([0, 1, 'c'], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py l[4:4] = ['d'] + call assert_equal([0, 1, 2, 3, 'd'], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py l[-1:2] = ['e'] + call assert_equal([0, 1, 2, 'e', 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py l[-10:2] = ['f'] + call assert_equal(['f', 2, 3], l) + + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + py l[2:-10] = ['g'] + call assert_equal([0, 1, 'g', 2, 3], l) + + let l = [] + py l = vim.bindeval('l') + py l[0:0] = ['h'] + call assert_equal(['h'], l) + + let l = range(8) + py l = vim.bindeval('l') + py l[2:6:2] = [10, 20] + call assert_equal([0, 1, 10, 3, 20, 5, 6, 7], l) + + let l = range(8) + py l = vim.bindeval('l') + py l[6:2:-2] = [10, 20] + call assert_equal([0, 1, 2, 3, 20, 5, 10, 7], l) + + let l = range(8) + py l = vim.bindeval('l') + py l[6:2] = () + call assert_equal([0, 1, 2, 3, 4, 5, 6, 7], l) + + let l = range(8) + py l = vim.bindeval('l') + py l[6:2:1] = () + call assert_equal([0, 1, 2, 3, 4, 5, 6, 7], l) + + let l = range(8) + py l = vim.bindeval('l') + py l[2:2:1] = () + call assert_equal([0, 1, 2, 3, 4, 5, 6, 7], l) +endfunc + +" Locked variables +func Test_python_lockedvar() + new + py cb = vim.current.buffer + let l = [0, 1, 2, 3] + py l = vim.bindeval('l') + lockvar! l + py << trim EOF + try: + l[2]='i' + except vim.error: + cb.append('l[2] threw vim.error: ' + emsg(sys.exc_info())) + EOF + call assert_equal(['', "l[2] threw vim.error: error:('list is locked',)"], + \ getline(1, '$')) + + " Try to concatenate a locked list + call AssertException(['py l += [4, 5]'], + \ 'Vim(python):vim.error: list is locked') + + call assert_equal([0, 1, 2, 3], l) + unlockvar! l + close! +endfunc + +" Test for calling a function +func Test_python_function_call() + func New(...) + return ['NewStart'] + a:000 + ['NewEnd'] + endfunc + + func DictNew(...) dict + return ['DictNewStart'] + a:000 + ['DictNewEnd', self] + endfunc + + new + let l = [function('New'), function('DictNew')] + py l = vim.bindeval('l') + py l.extend(list(l[0](1, 2, 3))) + call assert_equal([function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd'], l) + py l.extend(list(l[1](1, 2, 3, self={'a': 'b'}))) + call assert_equal([function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}], l) + py l.extend([l[0].name]) + call assert_equal([function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New'], l) + py ee('l[1](1, 2, 3)') + call assert_equal("l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: DictNew',)", getline(2)) + %d + py f = l[0] + delfunction New + py ee('f(1, 2, 3)') + call assert_equal("f(1, 2, 3):error:('Vim:E117: Unknown function: New',)", getline(2)) + close! + delfunction DictNew +endfunc + +func Test_python_float() + CheckFeature float + let l = [0.0] + py l = vim.bindeval('l') + py l.extend([0.0]) + call assert_equal([0.0, 0.0], l) +endfunc + +" Test for Dict key errors +func Test_python_dict_key_error() + let messages = [] + py << trim EOF + d = vim.bindeval('{}') + m = vim.bindeval('messages') + def em(expr, g=globals(), l=locals()): + try: + exec(expr, g, l) + except: + m.extend([sys.exc_type.__name__]) + + em('d["abc1"]') + em('d["abc1"]="\\0"') + em('d["abc1"]=vim') + em('d[""]=1') + em('d["a\\0b"]=1') + em('d[u"a\\0b"]=1') + em('d.pop("abc1")') + em('d.popitem()') + del em + del m + EOF + + call assert_equal(['KeyError', 'TypeError', 'TypeError', 'ValueError', + \ 'TypeError', 'TypeError', 'KeyError', 'KeyError'], messages) + unlet messages +endfunc + +" Test for locked and scope attributes +func Test_python_lock_scope_attr() + let d = {} | let dl = {} | lockvar dl + let res = [] + for s in split("d dl v: g:") + let name = tr(s, ':', 's') + execute 'py ' .. name .. ' = vim.bindeval("' .. s .. '")' + call add(res, s .. ' : ' .. join(map(['locked', 'scope'], + \ 'v:val .. ":" .. pyeval(name .. "." .. v:val)'), ';')) + endfor + call assert_equal(['d : locked:0;scope:0', 'dl : locked:1;scope:0', + \ 'v: : locked:2;scope:1', 'g: : locked:0;scope:2'], res) + + silent! let d.abc2 = 1 + silent! let dl.abc3 = 1 + py d.locked = True + py dl.locked = False + silent! let d.def = 1 + silent! let dl.def = 1 + call assert_equal({'abc2': 1}, d) + call assert_equal({'def': 1}, dl) + unlet d dl + + let l = [] | let ll = [] | lockvar ll + let res = [] + for s in split("l ll") + let name = tr(s, ':', 's') + execute 'py ' .. name .. '=vim.bindeval("' .. s .. '")' + call add(res, s .. ' : locked:' .. pyeval(name .. '.locked')) + endfor + call assert_equal(['l : locked:0', 'll : locked:1'], res) + + silent! call extend(l, [0]) + silent! call extend(ll, [0]) + py l.locked = True + py ll.locked = False + silent! call extend(l, [1]) + silent! call extend(ll, [1]) + call assert_equal([0], l) + call assert_equal([1], ll) + unlet l ll + + " Try changing an attribute of a fixed list + py a = vim.bindeval('v:argv') + call AssertException(['py a.locked = 0'], + \ 'Vim(python):TypeError: cannot modify fixed list') +endfunc + +" Test for pyeval() +func Test_python_pyeval() + let l = pyeval('range(3)') + call assert_equal([0, 1, 2], l) + + let d = pyeval('{"a": "b", "c": 1, "d": ["e"]}') + call assert_equal([['a', 'b'], ['c', 1], ['d', ['e']]], sort(items(d))) + + let v:errmsg = '' + call assert_equal(v:none, pyeval('None')) + call assert_equal('', v:errmsg) + + py v = vim.eval('test_null_function()') + call assert_equal(v:none, pyeval('v')) + + if has('float') + call assert_equal(0.0, pyeval('0.0')) + endif + + " Evaluate an invalid values + call AssertException(['let v = pyeval(''"\0"'')'], 'E859:') + call AssertException(['let v = pyeval(''{"\0" : 1}'')'], 'E859:') + call AssertException(['let v = pyeval("undefined_name")'], + \ "Vim(let):NameError: name 'undefined_name' is not defined") + call AssertException(['let v = pyeval("vim")'], 'E859:') +endfunc + +" Test for vim.bindeval() +func Test_python_vim_bindeval() + " Float + let f = 3.14 + py f = vim.bindeval('f') + call assert_equal(3.14, pyeval('f')) + + " Blob + let b = 0z12 + py b = vim.bindeval('b') + call assert_equal("\x12", pyeval('b')) + + " Bool + call assert_equal(1, pyeval("vim.bindeval('v:true')")) + call assert_equal(0, pyeval("vim.bindeval('v:false')")) + call assert_equal(v:none, pyeval("vim.bindeval('v:null')")) + call assert_equal(v:none, pyeval("vim.bindeval('v:none')")) +endfunc + +" threading +" Running pydo command (Test_pydo) before this test, stops the python thread +" from running. So this test should be run before the pydo test +func Test_aaa_python_threading() + let l = [0] + py l = vim.bindeval('l') + py << trim EOF + import threading + import time + + class T(threading.Thread): + def __init__(self): + threading.Thread.__init__(self) + self.t = 0 + self.running = True + + def run(self): + while self.running: + self.t += 1 + time.sleep(0.1) + + t = T() + del T + t.start() + EOF + + sleep 1 + py t.running = False + py t.join() + + " Check if the background thread is working. Count should be 10, but on a + " busy system (AppVeyor) it can be much lower. + py l[0] = t.t > 4 + py del time + py del threading + py del t + call assert_equal([1], l) +endfunc + +" settrace +func Test_python_settrace() + let l = [] + py l = vim.bindeval('l') + py << trim EOF + import sys + + def traceit(frame, event, arg): + global l + if event == "line": + l.extend([frame.f_lineno]) + return traceit + + def trace_main(): + for i in range(5): + pass + EOF + py sys.settrace(traceit) + py trace_main() + py sys.settrace(None) + py del traceit + py del trace_main + call assert_equal([1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1], l) +endfunc + +" Slice +func Test_python_list_slice() + py ll = vim.bindeval('[0, 1, 2, 3, 4, 5]') + py l = ll[:4] + call assert_equal([0, 1, 2, 3], pyeval('l')) + py l = ll[2:] + call assert_equal([2, 3, 4, 5], pyeval('l')) + py l = ll[:-4] + call assert_equal([0, 1], pyeval('l')) + py l = ll[-2:] + call assert_equal([4, 5], pyeval('l')) + py l = ll[2:4] + call assert_equal([2, 3], pyeval('l')) + py l = ll[4:2] + call assert_equal([], pyeval('l')) + py l = ll[-4:-2] + call assert_equal([2, 3], pyeval('l')) + py l = ll[-2:-4] + call assert_equal([], pyeval('l')) + py l = ll[:] + call assert_equal([0, 1, 2, 3, 4, 5], pyeval('l')) + py l = ll[0:6] + call assert_equal([0, 1, 2, 3, 4, 5], pyeval('l')) + py l = ll[-10:10] + call assert_equal([0, 1, 2, 3, 4, 5], pyeval('l')) + py l = ll[4:2:-1] + call assert_equal([4, 3], pyeval('l')) + py l = ll[::2] + call assert_equal([0, 2, 4], pyeval('l')) + py l = ll[4:2:1] + call assert_equal([], pyeval('l')) + + " Error case: Use an invalid index + call AssertException(['py ll[-10] = 5'], 'Vim(python):vim.error: internal error:') + + " Use a step value of 0 + call AssertException(['py ll[0:3:0] = [1, 2, 3]'], + \ 'Vim(python):ValueError: slice step cannot be zero') + + " Error case: Invalid slice type + call AssertException(["py x = ll['abc']"], + \ 'Vim(python):TypeError: index must be int or slice, not str') + py del l + + " Error case: List with a null list item + let l = [test_null_list()] + py ll = vim.bindeval('l') + call AssertException(["py x = ll[:]"], + \ 'Vim(python):SystemError: error return without exception set') +endfunc + +" Vars +func Test_python_vars() + let g:foo = 'bac' + let w:abc3 = 'def' + let b:baz = 'bar' + let t:bar = 'jkl' + try + throw "Abc" + catch /Abc/ + call assert_equal('Abc', pyeval('vim.vvars[''exception'']')) + endtry + call assert_equal('bac', pyeval('vim.vars[''foo'']')) + call assert_equal('def', pyeval('vim.current.window.vars[''abc3'']')) + call assert_equal('bar', pyeval('vim.current.buffer.vars[''baz'']')) + call assert_equal('jkl', pyeval('vim.current.tabpage.vars[''bar'']')) +endfunc + +" Options +" paste: boolean, global +" previewheight number, global +" operatorfunc: string, global +" number: boolean, window-local +" numberwidth: number, window-local +" colorcolumn: string, window-local +" statusline: string, window-local/global +" autoindent: boolean, buffer-local +" shiftwidth: number, buffer-local +" omnifunc: string, buffer-local +" preserveindent: boolean, buffer-local/global +" path: string, buffer-local/global +func Test_python_opts() + let g:res = [] + let g:bufs = [bufnr('%')] + new + let g:bufs += [bufnr('%')] + vnew + let g:bufs += [bufnr('%')] + wincmd j + vnew + let g:bufs += [bufnr('%')] + wincmd l + + func RecVars(opt) + let gval = string(eval('&g:' .. a:opt)) + let wvals = join(map(range(1, 4), + \ 'v:val .. ":" .. string(getwinvar(v:val, "&" .. a:opt))')) + let bvals = join(map(copy(g:bufs), + \ 'v:val .. ":" .. string(getbufvar(v:val, "&" .. a:opt))')) + call add(g:res, ' G: ' .. gval) + call add(g:res, ' W: ' .. wvals) + call add(g:res, ' B: ' .. wvals) + endfunc + + py << trim EOF + def e(s, g=globals(), l=locals()): + try: + exec(s, g, l) + except: + vim.command('return ' + repr(sys.exc_type.__name__)) + + def ev(s, g=globals(), l=locals()): + try: + return eval(s, g, l) + except: + vim.command('let exc=' + repr(sys.exc_type.__name__)) + return 0 + EOF + + func E(s) + python e(vim.eval('a:s')) + endfunc + + func Ev(s) + let r = pyeval('ev(vim.eval("a:s"))') + if exists('exc') + throw exc + endif + return r + endfunc + + py gopts1 = vim.options + py wopts1 = vim.windows[2].options + py wopts2 = vim.windows[0].options + py wopts3 = vim.windows[1].options + py bopts1 = vim.buffers[vim.bindeval("g:bufs")[2]].options + py bopts2 = vim.buffers[vim.bindeval("g:bufs")[1]].options + py bopts3 = vim.buffers[vim.bindeval("g:bufs")[0]].options + call add(g:res, 'wopts iters equal: ' .. + \ pyeval('list(wopts1) == list(wopts2)')) + call add(g:res, 'bopts iters equal: ' .. + \ pyeval('list(bopts1) == list(bopts2)')) + py gset = set(iter(gopts1)) + py wset = set(iter(wopts1)) + py bset = set(iter(bopts1)) + + set path=.,..,, + let lst = [] + let lst += [['paste', 1, 0, 1, 2, 1, 1, 0]] + let lst += [['previewheight', 5, 1, 6, 'a', 0, 1, 0]] + let lst += [['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0]] + let lst += [['number', 0, 1, 1, 0, 1, 0, 1]] + let lst += [['numberwidth', 2, 3, 5, -100, 0, 0, 1]] + let lst += [['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1]] + let lst += [['statusline', '1', '2', '4', 0, 0, 1, 1]] + let lst += [['autoindent', 0, 1, 1, 2, 1, 0, 2]] + let lst += [['shiftwidth', 0, 2, 1, 3, 0, 0, 2]] + let lst += [['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2]] + let lst += [['preserveindent', 0, 1, 1, 2, 1, 1, 2]] + let lst += [['path', '.,,', ',,', '.', 0, 0, 1, 2]] + for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst + py oname = vim.eval('oname') + py oval1 = vim.bindeval('oval1') + py oval2 = vim.bindeval('oval2') + py oval3 = vim.bindeval('oval3') + if invval is 0 || invval is 1 + py invval = bool(vim.bindeval('invval')) + else + py invval = vim.bindeval('invval') + endif + if bool + py oval1 = bool(oval1) + py oval2 = bool(oval2) + py oval3 = bool(oval3) + endif + call add(g:res, '>>> ' .. oname) + call add(g:res, ' g/w/b:' .. pyeval('oname in gset') .. '/' .. + \ pyeval('oname in wset') .. '/' .. pyeval('oname in bset')) + call add(g:res, ' g/w/b (in):' .. pyeval('oname in gopts1') .. '/' .. + \ pyeval('oname in wopts1') .. '/' .. pyeval('oname in bopts1')) + for v in ['gopts1', 'wopts1', 'bopts1'] + try + call add(g:res, ' p/' .. v .. ': ' .. Ev('repr(' .. v .. '[''' .. oname .. '''])')) + catch + call add(g:res, ' p/' .. v .. '! ' .. v:exception) + endtry + let r = E(v .. '[''' .. oname .. ''']=invval') + if r isnot 0 + call add(g:res, ' inv: ' .. string(invval) .. '! ' .. r) + endif + for vv in (v is# 'gopts1' ? [v] : [v, v[:-2] .. '2', v[:-2] .. '3']) + let val = substitute(vv, '^.opts', 'oval', '') + let r = E(vv .. '[''' .. oname .. ''']=' .. val) + if r isnot 0 + call add(g:res, ' ' .. vv .. '! ' .. r) + endif + endfor + endfor + call RecVars(oname) + for v in ['wopts3', 'bopts3'] + let r = E('del ' .. v .. '["' .. oname .. '"]') + if r isnot 0 + call add(g:res, ' del ' .. v .. '! ' .. r) + endif + endfor + call RecVars(oname) + endfor + delfunction RecVars + delfunction E + delfunction Ev + py del ev + py del e + only + for buf in g:bufs[1:] + execute 'bwipeout!' buf + endfor + py del gopts1 + py del wopts1 + py del wopts2 + py del wopts3 + py del bopts1 + py del bopts2 + py del bopts3 + py del oval1 + py del oval2 + py del oval3 + py del oname + py del invval + + let expected =<< trim END + wopts iters equal: 1 + bopts iters equal: 1 + >>> paste + g/w/b:1/0/0 + g/w/b (in):1/0/0 + p/gopts1: False + p/wopts1! KeyError + inv: 2! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1! KeyError + inv: 2! KeyError + bopts1! KeyError + bopts2! KeyError + bopts3! KeyError + G: 1 + W: 1:1 2:1 3:1 4:1 + B: 1:1 2:1 3:1 4:1 + del wopts3! KeyError + del bopts3! KeyError + G: 1 + W: 1:1 2:1 3:1 4:1 + B: 1:1 2:1 3:1 4:1 + >>> previewheight + g/w/b:1/0/0 + g/w/b (in):1/0/0 + p/gopts1: 12 + inv: 'a'! TypeError + p/wopts1! KeyError + inv: 'a'! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1! KeyError + inv: 'a'! KeyError + bopts1! KeyError + bopts2! KeyError + bopts3! KeyError + G: 5 + W: 1:5 2:5 3:5 4:5 + B: 1:5 2:5 3:5 4:5 + del wopts3! KeyError + del bopts3! KeyError + G: 5 + W: 1:5 2:5 3:5 4:5 + B: 1:5 2:5 3:5 4:5 + >>> operatorfunc + g/w/b:1/0/0 + g/w/b (in):1/0/0 + p/gopts1: '' + inv: 2! TypeError + p/wopts1! KeyError + inv: 2! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1! KeyError + inv: 2! KeyError + bopts1! KeyError + bopts2! KeyError + bopts3! KeyError + G: 'A' + W: 1:'A' 2:'A' 3:'A' 4:'A' + B: 1:'A' 2:'A' 3:'A' 4:'A' + del wopts3! KeyError + del bopts3! KeyError + G: 'A' + W: 1:'A' 2:'A' 3:'A' 4:'A' + B: 1:'A' 2:'A' 3:'A' 4:'A' + >>> number + g/w/b:0/1/0 + g/w/b (in):0/1/0 + p/gopts1! KeyError + inv: 0! KeyError + gopts1! KeyError + p/wopts1: False + p/bopts1! KeyError + inv: 0! KeyError + bopts1! KeyError + bopts2! KeyError + bopts3! KeyError + G: 0 + W: 1:1 2:1 3:0 4:0 + B: 1:1 2:1 3:0 4:0 + del wopts3! ValueError + del bopts3! KeyError + G: 0 + W: 1:1 2:1 3:0 4:0 + B: 1:1 2:1 3:0 4:0 + >>> numberwidth + g/w/b:0/1/0 + g/w/b (in):0/1/0 + p/gopts1! KeyError + inv: -100! KeyError + gopts1! KeyError + p/wopts1: 4 + inv: -100! error + p/bopts1! KeyError + inv: -100! KeyError + bopts1! KeyError + bopts2! KeyError + bopts3! KeyError + G: 4 + W: 1:3 2:5 3:2 4:4 + B: 1:3 2:5 3:2 4:4 + del wopts3! ValueError + del bopts3! KeyError + G: 4 + W: 1:3 2:5 3:2 4:4 + B: 1:3 2:5 3:2 4:4 + >>> colorcolumn + g/w/b:0/1/0 + g/w/b (in):0/1/0 + p/gopts1! KeyError + inv: 'abc4'! KeyError + gopts1! KeyError + p/wopts1: '' + inv: 'abc4'! error + p/bopts1! KeyError + inv: 'abc4'! KeyError + bopts1! KeyError + bopts2! KeyError + bopts3! KeyError + G: '' + W: 1:'+2' 2:'+3' 3:'+1' 4:'' + B: 1:'+2' 2:'+3' 3:'+1' 4:'' + del wopts3! ValueError + del bopts3! KeyError + G: '' + W: 1:'+2' 2:'+3' 3:'+1' 4:'' + B: 1:'+2' 2:'+3' 3:'+1' 4:'' + >>> statusline + g/w/b:1/1/0 + g/w/b (in):1/1/0 + p/gopts1: '' + inv: 0! TypeError + p/wopts1: None + inv: 0! TypeError + p/bopts1! KeyError + inv: 0! KeyError + bopts1! KeyError + bopts2! KeyError + bopts3! KeyError + G: '1' + W: 1:'2' 2:'4' 3:'1' 4:'1' + B: 1:'2' 2:'4' 3:'1' 4:'1' + del bopts3! KeyError + G: '1' + W: 1:'2' 2:'1' 3:'1' 4:'1' + B: 1:'2' 2:'1' 3:'1' 4:'1' + >>> autoindent + g/w/b:0/0/1 + g/w/b (in):0/0/1 + p/gopts1! KeyError + inv: 2! KeyError + gopts1! KeyError + p/wopts1! KeyError + inv: 2! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1: False + G: 0 + W: 1:0 2:1 3:0 4:1 + B: 1:0 2:1 3:0 4:1 + del wopts3! KeyError + del bopts3! ValueError + G: 0 + W: 1:0 2:1 3:0 4:1 + B: 1:0 2:1 3:0 4:1 + >>> shiftwidth + g/w/b:0/0/1 + g/w/b (in):0/0/1 + p/gopts1! KeyError + inv: 3! KeyError + gopts1! KeyError + p/wopts1! KeyError + inv: 3! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1: 8 + G: 8 + W: 1:0 2:2 3:8 4:1 + B: 1:0 2:2 3:8 4:1 + del wopts3! KeyError + del bopts3! ValueError + G: 8 + W: 1:0 2:2 3:8 4:1 + B: 1:0 2:2 3:8 4:1 + >>> omnifunc + g/w/b:0/0/1 + g/w/b (in):0/0/1 + p/gopts1! KeyError + inv: 1! KeyError + gopts1! KeyError + p/wopts1! KeyError + inv: 1! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1: '' + inv: 1! TypeError + G: '' + W: 1:'A' 2:'B' 3:'' 4:'C' + B: 1:'A' 2:'B' 3:'' 4:'C' + del wopts3! KeyError + del bopts3! ValueError + G: '' + W: 1:'A' 2:'B' 3:'' 4:'C' + B: 1:'A' 2:'B' 3:'' 4:'C' + >>> preserveindent + g/w/b:0/0/1 + g/w/b (in):0/0/1 + p/gopts1! KeyError + inv: 2! KeyError + gopts1! KeyError + p/wopts1! KeyError + inv: 2! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1: False + G: 0 + W: 1:0 2:1 3:0 4:1 + B: 1:0 2:1 3:0 4:1 + del wopts3! KeyError + del bopts3! ValueError + G: 0 + W: 1:0 2:1 3:0 4:1 + B: 1:0 2:1 3:0 4:1 + >>> path + g/w/b:1/0/1 + g/w/b (in):1/0/1 + p/gopts1: '.,..,,' + inv: 0! TypeError + p/wopts1! KeyError + inv: 0! KeyError + wopts1! KeyError + wopts2! KeyError + wopts3! KeyError + p/bopts1: None + inv: 0! TypeError + G: '.,,' + W: 1:'.,,' 2:',,' 3:'.,,' 4:'.' + B: 1:'.,,' 2:',,' 3:'.,,' 4:'.' + del wopts3! KeyError + G: '.,,' + W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' + B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' + END + + call assert_equal(expected, g:res) + unlet g:res + + call assert_equal(0, pyeval("'' in vim.options")) + + " use an empty key to index vim.options + call AssertException(["let v = pyeval(\"vim.options['']\")"], + \ 'Vim(let):ValueError: empty keys are not allowed') + call AssertException(["py vim.current.window.options[''] = 0"], + \ 'Vim(python):ValueError: empty keys are not allowed') + call AssertException(["py vim.current.window.options[{}] = 0"], + \ 'Vim(python):TypeError: expected str() or unicode() instance, but got dict') + + " set one of the number options to a very large number + let cmd = ["py vim.options['previewheight'] = 9999999999999999"] + call AssertException(cmd, 'OverflowError:') + + " unset a global-local string option + call AssertException(["py del vim.options['errorformat']"], + \ 'Vim(python):ValueError: unable to unset global option errorformat') +endfunc + +" Test for vim.buffer object +func Test_python_buffer() + new + call setline(1, "Hello\nWorld") + call assert_fails("let x = pyeval('vim.current.buffer[0]')", 'E859:') + %bw! + + edit Xfile1 + let bnr1 = bufnr() + py cb = vim.current.buffer + vnew Xfile2 + let bnr2 = bufnr() + call setline(1, ['First line', 'Second line', 'Third line']) + py b = vim.current.buffer + wincmd w + + " Test for getting lines from the buffer using a slice + call assert_equal(['First line'], pyeval('b[-10:1]')) + call assert_equal(['Third line'], pyeval('b[2:10]')) + call assert_equal([], pyeval('b[2:0]')) + call assert_equal([], pyeval('b[10:12]')) + call assert_equal([], pyeval('b[-10:-8]')) + + " Tests BufferAppend and BufferItem + py cb.append(b[0]) + call assert_equal(['First line'], getbufline(bnr1, 2)) + %d + + " Try to append using out-of-range line number + call AssertException(["py b.append('abc', 10)"], + \ 'Vim(python):IndexError: line number out of range') + + " Append a non-string item + call AssertException(["py b.append([22])"], + \ 'Vim(python):TypeError: expected str() or unicode() instance, but got int') + + " Tests BufferSlice and BufferAssSlice + py cb.append('abc5') # Will be overwritten + py cb[-1:] = b[:-2] + call assert_equal(['First line'], getbufline(bnr1, 2)) + %d + + " Test BufferLength and BufferAssSlice + py cb.append('def') # Will not be overwritten + py cb[len(cb):] = b[:] + call assert_equal(['def', 'First line', 'Second line', 'Third line'], + \ getbufline(bnr1, 2, '$')) + %d + + " Test BufferAssItem and BufferMark + call setbufline(bnr1, 1, ['one', 'two', 'three']) + call cursor(1, 3) + normal ma + py cb.append('ghi') # Will be overwritten + py cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1])) + call assert_equal(['(3, 2)'], getbufline(bnr1, 4)) + %d + + " Test BufferRepr + py cb.append(repr(cb) + repr(b)) + call assert_equal([''], getbufline(bnr1, 2)) + %d + + " Modify foreign buffer + py << trim EOF + b.append('foo') + b[0]='bar' + b[0:0]=['baz'] + vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number) + EOF + call assert_equal(['baz', 'bar', 'Second line', 'Third line', 'foo'], + \ getbufline(bnr2, 1, '$')) + %d + + " Test assigning to name property + augroup BUFS + autocmd BufFilePost * python cb.append(vim.eval('expand("")') + ':BufFilePost:' + vim.eval('bufnr("%")')) + autocmd BufFilePre * python cb.append(vim.eval('expand("")') + ':BufFilePre:' + vim.eval('bufnr("%")')) + augroup END + py << trim EOF + import os + old_name = cb.name + cb.name = 'foo' + cb.append(cb.name[-11:].replace(os.path.sep, '/')) + b.name = 'bar' + cb.append(b.name[-11:].replace(os.path.sep, '/')) + cb.name = old_name + cb.append(cb.name[-14:].replace(os.path.sep, '/')) + del old_name + EOF + call assert_equal([bnr1 .. ':BufFilePre:' .. bnr1, + \ bnr1 .. ':BufFilePost:' .. bnr1, + \ 'testdir/foo', + \ bnr2 .. ':BufFilePre:' .. bnr2, + \ bnr2 .. ':BufFilePost:' .. bnr2, + \ 'testdir/bar', + \ bnr1 .. ':BufFilePre:' .. bnr1, + \ bnr1 .. ':BufFilePost:' .. bnr1, + \ 'testdir/Xfile1'], getbufline(bnr1, 2, '$')) + %d + + " Test CheckBuffer + py << trim EOF + for _b in vim.buffers: + if _b is not cb: + vim.command('bwipeout! ' + str(_b.number)) + del _b + cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid))) + EOF + call assert_equal('valid: b:False, cb:True', getline(2)) + %d + + py << trim EOF + for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")', 'b.name = "!"'): + try: + exec(expr) + except vim.error: + pass + else: + # Usually a SEGV here + # Should not happen in any case + cb.append('No exception for ' + expr) + vim.command('cd .') + del b + EOF + call assert_equal([''], getline(1, '$')) + + " Delete all the lines in a buffer + call setline(1, ['a', 'b', 'c']) + py vim.current.buffer[:] = [] + call assert_equal([''], getline(1, '$')) + + " Test for modifying a 'nomodifiable' buffer + setlocal nomodifiable + call AssertException(["py vim.current.buffer[0] = 'abc'"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer[0] = None"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer[:] = None"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer[:] = []"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer.append('abc')"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + call AssertException(["py vim.current.buffer.append([])"], + \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") + setlocal modifiable + + augroup BUFS + autocmd! + augroup END + augroup! BUFS + %bw! + + " Range object for a deleted buffer + new Xfile + call setline(1, ['one', 'two', 'three']) + py b = vim.current.buffer + py r = vim.current.buffer.range(0, 2) + call assert_equal('', pyeval('repr(r)')) + %bw! + call AssertException(['py r[:] = []'], + \ 'Vim(python):vim.error: attempt to refer to deleted buffer') + call assert_match('