diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 3fcb51eabf..e0572aad4b 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2016 Apr 12 +*eval.txt* For Vim version 7.4. Last change: 2016 Apr 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -61,9 +61,9 @@ Funcref A reference to a function |Funcref|. Special |v:false|, |v:true|, |v:none| and |v:null|. *Special* -Job Used for a job, see |job_start()|. *Job* +Job Used for a job, see |job_start()|. *Job* *Jobs* -Channel Used for a channel, see |ch_open()|. *Channel* +Channel Used for a channel, see |ch_open()|. *Channel* *Channels* The Number and String types are converted automatically, depending on how they are used. @@ -1723,6 +1723,9 @@ v:termresponse The escape sequence returned by the terminal for the |t_RV| always 95 or bigger). Pc is always zero. {only when compiled with |+termresponse| feature} + *v:testing* *testing-variable* +v:testing Must be set before using `garbagecollect_for_testing()`. + *v:this_session* *this_session-variable* v:this_session Full filename of the last loaded or saved session file. See |:mksession|. It is allowed to set this variable. When no @@ -1788,133 +1791,137 @@ See |function-list| for a list grouped by what the function is used for. USAGE RESULT DESCRIPTION ~ -abs( {expr}) Float or Number absolute value of {expr} -acos( {expr}) Float arc cosine of {expr} -add( {list}, {item}) List append {item} to |List| {list} -alloc_fail( {id}, {countdown}, {repeat}) +abs({expr}) Float or Number absolute value of {expr} +acos({expr}) Float arc cosine of {expr} +add({list}, {item}) List append {item} to |List| {list} +alloc_fail({id}, {countdown}, {repeat}) none make memory allocation fail -and( {expr}, {expr}) Number bitwise AND -append( {lnum}, {string}) Number append {string} below line {lnum} -append( {lnum}, {list}) Number append lines {list} below line {lnum} +and({expr}, {expr}) Number bitwise AND +append({lnum}, {string}) Number append {string} below line {lnum} +append({lnum}, {list}) Number append lines {list} below line {lnum} argc() Number number of files in the argument list argidx() Number current index in the argument list -arglistid( [{winnr} [, {tabnr}]]) - Number argument list id -argv( {nr}) String {nr} entry of the argument list +arglistid([{winnr} [, {tabnr}]]) Number argument list id +argv({nr}) String {nr} entry of the argument list argv() List the argument list -assert_equal( {exp}, {act} [, {msg}]) none assert {exp} is equal to {act} -assert_exception( {error} [, {msg}]) none assert {error} is in v:exception -assert_fails( {cmd} [, {error}]) none assert {cmd} fails -assert_false( {actual} [, {msg}]) none assert {actual} is false -assert_match( {pat}, {text} [, {msg}]) none assert {pat} matches {text} -assert_notequal( {exp}, {act} [, {msg}]) none assert {exp} is not equal {act} -assert_notmatch( {pat}, {text} [, {msg}]) none assert {pat} not matches {text} -assert_true( {actual} [, {msg}]) none assert {actual} is true -asin( {expr}) Float arc sine of {expr} -atan( {expr}) Float arc tangent of {expr} -atan2( {expr}, {expr}) Float arc tangent of {expr1} / {expr2} -browse( {save}, {title}, {initdir}, {default}) +assert_equal({exp}, {act} [, {msg}]) none assert {exp} is equal to {act} +assert_exception({error} [, {msg}]) none assert {error} is in v:exception +assert_fails({cmd} [, {error}]) none assert {cmd} fails +assert_false({actual} [, {msg}]) none assert {actual} is false +assert_match({pat}, {text} [, {msg}]) none assert {pat} matches {text} +assert_notequal({exp}, {act} [, {msg}]) none assert {exp} is not equal {act} +assert_notmatch({pat}, {text} [, {msg}]) none assert {pat} not matches {text} +assert_true({actual} [, {msg}]) none assert {actual} is true +asin({expr}) Float arc sine of {expr} +atan({expr}) Float arc tangent of {expr} +atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2} +browse({save}, {title}, {initdir}, {default}) String put up a file requester -browsedir( {title}, {initdir}) String put up a directory requester -bufexists( {expr}) Number TRUE if buffer {expr} exists -buflisted( {expr}) Number TRUE if buffer {expr} is listed -bufloaded( {expr}) Number TRUE if buffer {expr} is loaded -bufname( {expr}) String Name of the buffer {expr} -bufnr( {expr} [, {create}]) Number Number of the buffer {expr} -bufwinnr( {expr}) Number window number of buffer {expr} -byte2line( {byte}) Number line number at byte count {byte} -byteidx( {expr}, {nr}) Number byte index of {nr}'th char in {expr} -byteidxcomp( {expr}, {nr}) Number byte index of {nr}'th char in {expr} -call( {func}, {arglist} [, {dict}]) +browsedir({title}, {initdir}) String put up a directory requester +bufexists({expr}) Number TRUE if buffer {expr} exists +buflisted({expr}) Number TRUE if buffer {expr} is listed +bufloaded({expr}) Number TRUE if buffer {expr} is loaded +bufname({expr}) String Name of the buffer {expr} +bufnr({expr} [, {create}]) Number Number of the buffer {expr} +bufwinnr({expr}) Number window number of buffer {expr} +byte2line({byte}) Number line number at byte count {byte} +byteidx({expr}, {nr}) Number byte index of {nr}'th char in {expr} +byteidxcomp({expr}, {nr}) Number byte index of {nr}'th char in {expr} +call({func}, {arglist} [, {dict}]) any call {func} with arguments {arglist} -ceil( {expr}) Float round {expr} up -ch_close( {handle}) none close {handle} -ch_evalexpr( {handle}, {expr} [, {options}]) +ceil({expr}) Float round {expr} up +ch_close({handle}) none close {handle} +ch_evalexpr({handle}, {expr} [, {options}]) any evaluate {expr} on JSON {handle} -ch_evalraw( {handle}, {string} [, {options}]) +ch_evalraw({handle}, {string} [, {options}]) any evaluate {string} on raw {handle} -ch_getbufnr( {handle}, {what}) Number get buffer number for {handle}/{what} -ch_getjob( {channel}) Job get the Job of {channel} -ch_info( {handle}) String info about channel {handle} -ch_log( {msg} [, {handle}]) none write {msg} in the channel log file -ch_logfile( {fname} [, {mode}]) none start logging channel activity -ch_open( {address} [, {options}]) Channel open a channel to {address} -ch_read( {handle} [, {options}]) String read from {handle} -ch_readraw( {handle} [, {options}]) String read raw from {handle} -ch_sendexpr( {handle}, {expr} [, {options}]) +ch_getbufnr({handle}, {what}) Number get buffer number for {handle}/{what} +ch_getjob({channel}) Job get the Job of {channel} +ch_info({handle}) String info about channel {handle} +ch_log({msg} [, {handle}]) none write {msg} in the channel log file +ch_logfile({fname} [, {mode}]) none start logging channel activity +ch_open({address} [, {options}]) + Channel open a channel to {address} +ch_read({handle} [, {options}]) String read from {handle} +ch_readraw({handle} [, {options}]) + String read raw from {handle} +ch_sendexpr({handle}, {expr} [, {options}]) any send {expr} over JSON {handle} -ch_sendraw( {handle}, {string} [, {options}]) +ch_sendraw({handle}, {string} [, {options}]) any send {string} over raw {handle} -ch_setoptions( {handle}, {options}) none set options for {handle} -ch_status( {handle}) String status of channel {handle} +ch_setoptions({handle}, {options}) + none set options for {handle} +ch_status({handle}) String status of channel {handle} changenr() Number current change number -char2nr( {expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} -cindent( {lnum}) Number C indent for line {lnum} +char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} +cindent({lnum}) Number C indent for line {lnum} clearmatches() none clear all matches -col( {expr}) Number column nr of cursor or mark -complete( {startcol}, {matches}) none set Insert mode completion -complete_add( {expr}) Number add completion match +col({expr}) Number column nr of cursor or mark +complete({startcol}, {matches}) none set Insert mode completion +complete_add({expr}) Number add completion match complete_check() Number check for key typed during completion -confirm( {msg} [, {choices} [, {default} [, {type}]]]) +confirm({msg} [, {choices} [, {default} [, {type}]]]) Number number of choice picked by user -copy( {expr}) any make a shallow copy of {expr} -cos( {expr}) Float cosine of {expr} -cosh( {expr}) Float hyperbolic cosine of {expr} -count( {list}, {expr} [, {ic} [, {start}]]) +copy({expr}) any make a shallow copy of {expr} +cos({expr}) Float cosine of {expr} +cosh({expr}) Float hyperbolic cosine of {expr} +count({list}, {expr} [, {ic} [, {start}]]) Number count how many {expr} are in {list} -cscope_connection( [{num} , {dbpath} [, {prepend}]]) +cscope_connection([{num} , {dbpath} [, {prepend}]]) Number checks existence of cscope connection -cursor( {lnum}, {col} [, {off}]) +cursor({lnum}, {col} [, {off}]) Number move cursor to {lnum}, {col}, {off} -cursor( {list}) Number move cursor to position in {list} -deepcopy( {expr} [, {noref}]) any make a full copy of {expr} -delete( {fname} [, {flags}]) Number delete the file or directory {fname} +cursor({list}) Number move cursor to position in {list} +deepcopy({expr} [, {noref}]) any make a full copy of {expr} +delete({fname} [, {flags}]) Number delete the file or directory {fname} did_filetype() Number TRUE if FileType autocommand event used -diff_filler( {lnum}) Number diff filler lines about {lnum} -diff_hlID( {lnum}, {col}) Number diff highlighting at {lnum}/{col} -disable_char_avail_for_testing( {expr}) none test without typeahead -empty( {expr}) Number TRUE if {expr} is empty -escape( {string}, {chars}) String escape {chars} in {string} with '\' -eval( {string}) any evaluate {string} into its value +diff_filler({lnum}) Number diff filler lines about {lnum} +diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col} +disable_char_avail_for_testing({expr}) + none test without typeahead +empty({expr}) Number TRUE if {expr} is empty +escape({string}, {chars}) String escape {chars} in {string} with '\' +eval({string}) any evaluate {string} into its value eventhandler() Number TRUE if inside an event handler -executable( {expr}) Number 1 if executable {expr} exists -exepath( {expr}) String full path of the command {expr} -exists( {expr}) Number TRUE if {expr} exists -extend( {expr1}, {expr2} [, {expr3}]) +executable({expr}) Number 1 if executable {expr} exists +exepath({expr}) String full path of the command {expr} +exists({expr}) Number TRUE if {expr} exists +extend({expr1}, {expr2} [, {expr3}]) List/Dict insert items of {expr2} into {expr1} -exp( {expr}) Float exponential of {expr} -expand( {expr} [, {nosuf} [, {list}]]) +exp({expr}) Float exponential of {expr} +expand({expr} [, {nosuf} [, {list}]]) any expand special keywords in {expr} -feedkeys( {string} [, {mode}]) Number add key sequence to typeahead buffer -filereadable( {file}) Number TRUE if {file} is a readable file -filewritable( {file}) Number TRUE if {file} is a writable file -filter( {expr}, {string}) List/Dict remove items from {expr} where +feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer +filereadable({file}) Number TRUE if {file} is a readable file +filewritable({file}) Number TRUE if {file} is a writable file +filter({expr}, {string}) List/Dict remove items from {expr} where {string} is 0 -finddir( {name}[, {path}[, {count}]]) +finddir({name}[, {path}[, {count}]]) String find directory {name} in {path} -findfile( {name}[, {path}[, {count}]]) +findfile({name}[, {path}[, {count}]]) String find file {name} in {path} -float2nr( {expr}) Number convert Float {expr} to a Number -floor( {expr}) Float round {expr} down -fmod( {expr1}, {expr2}) Float remainder of {expr1} / {expr2} -fnameescape( {fname}) String escape special characters in {fname} -fnamemodify( {fname}, {mods}) String modify file name -foldclosed( {lnum}) Number first line of fold at {lnum} if closed -foldclosedend( {lnum}) Number last line of fold at {lnum} if closed -foldlevel( {lnum}) Number fold level at {lnum} +float2nr({expr}) Number convert Float {expr} to a Number +floor({expr}) Float round {expr} down +fmod({expr1}, {expr2}) Float remainder of {expr1} / {expr2} +fnameescape({fname}) String escape special characters in {fname} +fnamemodify({fname}, {mods}) String modify file name +foldclosed({lnum}) Number first line of fold at {lnum} if closed +foldclosedend({lnum}) Number last line of fold at {lnum} if closed +foldlevel({lnum}) Number fold level at {lnum} foldtext() String line displayed for closed fold -foldtextresult( {lnum}) String text for closed fold at {lnum} +foldtextresult({lnum}) String text for closed fold at {lnum} foreground() Number bring the Vim window to the foreground function({name} [, {arglist}] [, {dict}]) Funcref reference to function {name} -garbagecollect( [{atexit}]) none free memory, breaking cyclic references -get( {list}, {idx} [, {def}]) any get item {idx} from {list} or {def} -get( {dict}, {key} [, {def}]) any get item {key} from {dict} or {def} -getbufline( {expr}, {lnum} [, {end}]) +garbagecollect([{atexit}]) none free memory, breaking cyclic references +garbagecollect_for_testing() none free memory right now +get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def} +get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def} +getbufline({expr}, {lnum} [, {end}]) List lines {lnum} to {end} of buffer {expr} -getbufvar( {expr}, {varname} [, {def}]) +getbufvar({expr}, {varname} [, {def}]) any variable {varname} in buffer {expr} -getchar( [expr]) Number get one character from the user +getchar([expr]) Number get one character from the user getcharmod() Number modifiers for the last typed character getcharsearch() Dict last character search getcmdline() String return the current command-line @@ -1922,268 +1929,271 @@ getcmdpos() Number return cursor position in command-line getcmdtype() String return current command-line type getcmdwintype() String return current command-line window type getcurpos() List position of the cursor -getcwd( [{winnr} [, {tabnr}]]) String get the current working directory -getfontname( [{name}]) String name of font being used -getfperm( {fname}) String file permissions of file {fname} -getfsize( {fname}) Number size in bytes of file {fname} -getftime( {fname}) Number last modification time of file -getftype( {fname}) String description of type of file {fname} -getline( {lnum}) String line {lnum} of current buffer -getline( {lnum}, {end}) List lines {lnum} to {end} of current buffer -getloclist( {nr}) List list of location list items +getcwd([{winnr} [, {tabnr}]]) String get the current working directory +getfontname([{name}]) String name of font being used +getfperm({fname}) String file permissions of file {fname} +getfsize({fname}) Number size in bytes of file {fname} +getftime({fname}) Number last modification time of file +getftype({fname}) String description of type of file {fname} +getline({lnum}) String line {lnum} of current buffer +getline({lnum}, {end}) List lines {lnum} to {end} of current buffer +getloclist({nr}) List list of location list items getmatches() List list of current matches getpid() Number process ID of Vim -getpos( {expr}) List position of cursor, mark, etc. +getpos({expr}) List position of cursor, mark, etc. getqflist() List list of quickfix items -getreg( [{regname} [, 1 [, {list}]]]) +getreg([{regname} [, 1 [, {list}]]]) String or List contents of register -getregtype( [{regname}]) String type of register -gettabvar( {nr}, {varname} [, {def}]) +getregtype([{regname}]) String type of register +gettabvar({nr}, {varname} [, {def}]) any variable {varname} in tab {nr} or {def} -gettabwinvar( {tabnr}, {winnr}, {name} [, {def}]) +gettabwinvar({tabnr}, {winnr}, {name} [, {def}]) any {name} in {winnr} in tab page {tabnr} getwinposx() Number X coord in pixels of GUI Vim window getwinposy() Number Y coord in pixels of GUI Vim window -getwinvar( {nr}, {varname} [, {def}]) +getwinvar({nr}, {varname} [, {def}]) any variable {varname} in window {nr} -glob( {expr} [, {nosuf} [, {list} [, {alllinks}]]]) +glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) any expand file wildcards in {expr} -glob2regpat( {expr}) String convert a glob pat into a search pat -globpath( {path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]]) +glob2regpat({expr}) String convert a glob pat into a search pat +globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]]) String do glob({expr}) for all dirs in {path} -has( {feature}) Number TRUE if feature {feature} supported -has_key( {dict}, {key}) Number TRUE if {dict} has entry {key} -haslocaldir( [{winnr} [, {tabnr}]]) +has({feature}) Number TRUE if feature {feature} supported +has_key({dict}, {key}) Number TRUE if {dict} has entry {key} +haslocaldir([{winnr} [, {tabnr}]]) Number TRUE if the window executed |:lcd| -hasmapto( {what} [, {mode} [, {abbr}]]) +hasmapto({what} [, {mode} [, {abbr}]]) Number TRUE if mapping to {what} exists -histadd( {history}, {item}) String add an item to a history -histdel( {history} [, {item}]) String remove an item from a history -histget( {history} [, {index}]) String get the item {index} from a history -histnr( {history}) Number highest index of a history -hlexists( {name}) Number TRUE if highlight group {name} exists -hlID( {name}) Number syntax ID of highlight group {name} +histadd({history}, {item}) String add an item to a history +histdel({history} [, {item}]) String remove an item from a history +histget({history} [, {index}]) String get the item {index} from a history +histnr({history}) Number highest index of a history +hlexists({name}) Number TRUE if highlight group {name} exists +hlID({name}) Number syntax ID of highlight group {name} hostname() String name of the machine Vim is running on -iconv( {expr}, {from}, {to}) String convert encoding of {expr} -indent( {lnum}) Number indent of line {lnum} -index( {list}, {expr} [, {start} [, {ic}]]) +iconv({expr}, {from}, {to}) String convert encoding of {expr} +indent({lnum}) Number indent of line {lnum} +index({list}, {expr} [, {start} [, {ic}]]) Number index in {list} where {expr} appears -input( {prompt} [, {text} [, {completion}]]) +input({prompt} [, {text} [, {completion}]]) String get input from the user -inputdialog( {p} [, {t} [, {c}]]) String like input() but in a GUI dialog -inputlist( {textlist}) Number let the user pick from a choice list +inputdialog({prompt} [, {text} [, {completion}]]]) + String like input() but in a GUI dialog +inputlist({textlist}) Number let the user pick from a choice list inputrestore() Number restore typeahead inputsave() Number save and clear typeahead -inputsecret( {prompt} [, {text}]) String like input() but hiding the text -insert( {list}, {item} [, {idx}]) List insert {item} in {list} [before {idx}] -invert( {expr}) Number bitwise invert -isdirectory( {directory}) Number TRUE if {directory} is a directory -islocked( {expr}) Number TRUE if {expr} is locked -isnan( {expr}) Number TRUE if {expr} is NaN -items( {dict}) List key-value pairs in {dict} -job_getchannel( {job}) Channel get the channel handle for {job} -job_info( {job}) Dict get information about {job} -job_setoptions( {job}, {options}) none set options for {job} -job_start( {command} [, {options}]) Job start a job -job_status( {job}) String get the status of {job} -job_stop( {job} [, {how}]) Number stop {job} -join( {list} [, {sep}]) String join {list} items into one String -js_decode( {string}) any decode JS style JSON -js_encode( {expr}) String encode JS style JSON -json_decode( {string}) any decode JSON -json_encode( {expr}) String encode JSON -keys( {dict}) List keys in {dict} -len( {expr}) Number the length of {expr} -libcall( {lib}, {func}, {arg}) String call {func} in library {lib} with {arg} -libcallnr( {lib}, {func}, {arg}) Number idem, but return a Number -line( {expr}) Number line nr of cursor, last line or mark -line2byte( {lnum}) Number byte count of line {lnum} -lispindent( {lnum}) Number Lisp indent for line {lnum} +inputsecret({prompt} [, {text}]) String like input() but hiding the text +insert({list}, {item} [, {idx}]) List insert {item} in {list} [before {idx}] +invert({expr}) Number bitwise invert +isdirectory({directory}) Number TRUE if {directory} is a directory +islocked({expr}) Number TRUE if {expr} is locked +isnan({expr}) Number TRUE if {expr} is NaN +items({dict}) List key-value pairs in {dict} +job_getchannel({job}) Channel get the channel handle for {job} +job_info({job}) Dict get information about {job} +job_setoptions({job}, {options}) none set options for {job} +job_start({command} [, {options}]) + Job start a job +job_status({job}) String get the status of {job} +job_stop({job} [, {how}]) Number stop {job} +join({list} [, {sep}]) String join {list} items into one String +js_decode({string}) any decode JS style JSON +js_encode({expr}) String encode JS style JSON +json_decode({string}) any decode JSON +json_encode({expr}) String encode JSON +keys({dict}) List keys in {dict} +len({expr}) Number the length of {expr} +libcall({lib}, {func}, {arg}) String call {func} in library {lib} with {arg} +libcallnr({lib}, {func}, {arg}) Number idem, but return a Number +line({expr}) Number line nr of cursor, last line or mark +line2byte({lnum}) Number byte count of line {lnum} +lispindent({lnum}) Number Lisp indent for line {lnum} localtime() Number current time -log( {expr}) Float natural logarithm (base e) of {expr} -log10( {expr}) Float logarithm of Float {expr} to base 10 -luaeval( {expr}[, {expr}]) any evaluate |Lua| expression -map( {expr}, {string}) List/Dict change each item in {expr} to {expr} -maparg( {name}[, {mode} [, {abbr} [, {dict}]]]) +log({expr}) Float natural logarithm (base e) of {expr} +log10({expr}) Float logarithm of Float {expr} to base 10 +luaeval({expr}[, {expr}]) any evaluate |Lua| expression +map({expr}, {string}) List/Dict change each item in {expr} to {expr} +maparg({name}[, {mode} [, {abbr} [, {dict}]]]) String or Dict rhs of mapping {name} in mode {mode} -mapcheck( {name}[, {mode} [, {abbr}]]) +mapcheck({name}[, {mode} [, {abbr}]]) String check for mappings matching {name} -match( {expr}, {pat}[, {start}[, {count}]]) +match({expr}, {pat}[, {start}[, {count}]]) Number position where {pat} matches in {expr} -matchadd( {group}, {pattern}[, {priority}[, {id} [, {dict}]]]) +matchadd({group}, {pattern}[, {priority}[, {id} [, {dict}]]]) Number highlight {pattern} with {group} -matchaddpos( {group}, {pos}[, {priority}[, {id}[, {dict}]]]) +matchaddpos({group}, {pos}[, {priority}[, {id}[, {dict}]]]) Number highlight positions with {group} -matcharg( {nr}) List arguments of |:match| -matchdelete( {id}) Number delete match identified by {id} -matchend( {expr}, {pat}[, {start}[, {count}]]) +matcharg({nr}) List arguments of |:match| +matchdelete({id}) Number delete match identified by {id} +matchend({expr}, {pat}[, {start}[, {count}]]) Number position where {pat} ends in {expr} -matchlist( {expr}, {pat}[, {start}[, {count}]]) +matchlist({expr}, {pat}[, {start}[, {count}]]) List match and submatches of {pat} in {expr} -matchstr( {expr}, {pat}[, {start}[, {count}]]) +matchstr({expr}, {pat}[, {start}[, {count}]]) String {count}'th match of {pat} in {expr} -matchstrpos( {expr}, {pat}[, {start}[, {count}]]) +matchstrpos({expr}, {pat}[, {start}[, {count}]]) List {count}'th match of {pat} in {expr} -max( {list}) Number maximum value of items in {list} -min( {list}) Number minimum value of items in {list} -mkdir( {name} [, {path} [, {prot}]]) +max({list}) Number maximum value of items in {list} +min({list}) Number minimum value of items in {list} +mkdir({name} [, {path} [, {prot}]]) Number create directory {name} -mode( [expr]) String current editing mode -mzeval( {expr}) any evaluate |MzScheme| expression -nextnonblank( {lnum}) Number line nr of non-blank line >= {lnum} -nr2char( {expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr} -or( {expr}, {expr}) Number bitwise OR -pathshorten( {expr}) String shorten directory names in a path -perleval( {expr}) any evaluate |Perl| expression -pow( {x}, {y}) Float {x} to the power of {y} -prevnonblank( {lnum}) Number line nr of non-blank line <= {lnum} -printf( {fmt}, {expr1}...) String format text +mode([expr]) String current editing mode +mzeval({expr}) any evaluate |MzScheme| expression +nextnonblank({lnum}) Number line nr of non-blank line >= {lnum} +nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr} +or({expr}, {expr}) Number bitwise OR +pathshorten({expr}) String shorten directory names in a path +perleval({expr}) any evaluate |Perl| expression +pow({x}, {y}) Float {x} to the power of {y} +prevnonblank({lnum}) Number line nr of non-blank line <= {lnum} +printf({fmt}, {expr1}...) String format text pumvisible() Number whether popup menu is visible -pyeval( {expr}) any evaluate |Python| expression -py3eval( {expr}) any evaluate |python3| expression -range( {expr} [, {max} [, {stride}]]) +pyeval({expr}) any evaluate |Python| expression +py3eval({expr}) any evaluate |python3| expression +range({expr} [, {max} [, {stride}]]) List items from {expr} to {max} -readfile( {fname} [, {binary} [, {max}]]) +readfile({fname} [, {binary} [, {max}]]) List get list of lines from file {fname} -reltime( [{start} [, {end}]]) List get time value -reltimefloat( {time}) Float turn the time value into a Float -reltimestr( {time}) String turn time value into a String -remote_expr( {server}, {string} [, {idvar}]) +reltime([{start} [, {end}]]) List get time value +reltimefloat({time}) Float turn the time value into a Float +reltimestr({time}) String turn time value into a String +remote_expr({server}, {string} [, {idvar}]) String send expression -remote_foreground( {server}) Number bring Vim server to the foreground -remote_peek( {serverid} [, {retvar}]) +remote_foreground({server}) Number bring Vim server to the foreground +remote_peek({serverid} [, {retvar}]) Number check for reply string -remote_read( {serverid}) String read reply string -remote_send( {server}, {string} [, {idvar}]) +remote_read({serverid}) String read reply string +remote_send({server}, {string} [, {idvar}]) String send key sequence -remove( {list}, {idx} [, {end}]) any remove items {idx}-{end} from {list} -remove( {dict}, {key}) any remove entry {key} from {dict} -rename( {from}, {to}) Number rename (move) file from {from} to {to} -repeat( {expr}, {count}) String repeat {expr} {count} times -resolve( {filename}) String get filename a shortcut points to -reverse( {list}) List reverse {list} in-place -round( {expr}) Float round off {expr} -screenattr( {row}, {col}) Number attribute at screen position -screenchar( {row}, {col}) Number character at screen position +remove({list}, {idx} [, {end}]) any remove items {idx}-{end} from {list} +remove({dict}, {key}) any remove entry {key} from {dict} +rename({from}, {to}) Number rename (move) file from {from} to {to} +repeat({expr}, {count}) String repeat {expr} {count} times +resolve({filename}) String get filename a shortcut points to +reverse({list}) List reverse {list} in-place +round({expr}) Float round off {expr} +screenattr({row}, {col}) Number attribute at screen position +screenchar({row}, {col}) Number character at screen position screencol() Number current cursor column screenrow() Number current cursor row -search( {pattern} [, {flags} [, {stopline} [, {timeout}]]]) +search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) Number search for {pattern} -searchdecl( {name} [, {global} [, {thisblock}]]) +searchdecl({name} [, {global} [, {thisblock}]]) Number search for variable declaration -searchpair( {start}, {middle}, {end} [, {flags} [, {skip} [...]]]) +searchpair({start}, {middle}, {end} [, {flags} [, {skip} [...]]]) Number search for other end of start/end pair -searchpairpos( {start}, {middle}, {end} [, {flags} [, {skip} [...]]]) +searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [...]]]) List search for other end of start/end pair -searchpos( {pattern} [, {flags} [, {stopline} [, {timeout}]]]) +searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) List search for {pattern} -server2client( {clientid}, {string}) +server2client({clientid}, {string}) Number send reply string serverlist() String get a list of available servers -setbufvar( {expr}, {varname}, {val}) set {varname} in buffer {expr} to {val} -setcharsearch( {dict}) Dict set character search from {dict} -setcmdpos( {pos}) Number set cursor position in command-line -setfperm( {fname}, {mode}) Number set {fname} file permissions to {mode} -setline( {lnum}, {line}) Number set line {lnum} to {line} -setloclist( {nr}, {list}[, {action}]) +setbufvar({expr}, {varname}, {val}) + none set {varname} in buffer {expr} to {val} +setcharsearch({dict}) Dict set character search from {dict} +setcmdpos({pos}) Number set cursor position in command-line +setfperm({fname}, {mode}) Number set {fname} file permissions to {mode} +setline({lnum}, {line}) Number set line {lnum} to {line} +setloclist({nr}, {list}[, {action}]) Number modify location list using {list} -setmatches( {list}) Number restore a list of matches -setpos( {expr}, {list}) Number set the {expr} position to {list} -setqflist( {list}[, {action}]) Number modify quickfix list using {list} -setreg( {n}, {v}[, {opt}]) Number set register to value and type -settabvar( {nr}, {varname}, {val}) set {varname} in tab page {nr} to {val} -settabwinvar( {tabnr}, {winnr}, {varname}, {val}) set {varname} in window - {winnr} in tab page {tabnr} to {val} -setwinvar( {nr}, {varname}, {val}) set {varname} in window {nr} to {val} -sha256( {string}) String SHA256 checksum of {string} -shellescape( {string} [, {special}]) +setmatches({list}) Number restore a list of matches +setpos({expr}, {list}) Number set the {expr} position to {list} +setqflist({list}[, {action}]) Number modify quickfix list using {list} +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}) + none set {varname} in window {winnr} in tab + page {tabnr} to {val} +setwinvar({nr}, {varname}, {val}) none set {varname} in window {nr} to {val} +sha256({string}) String SHA256 checksum of {string} +shellescape({string} [, {special}]) String escape {string} for use as shell command argument shiftwidth() Number effective value of 'shiftwidth' -simplify( {filename}) String simplify filename as much as possible -sin( {expr}) Float sine of {expr} -sinh( {expr}) Float hyperbolic sine of {expr} -sort( {list} [, {func} [, {dict}]]) +simplify({filename}) String simplify filename as much as possible +sin({expr}) Float sine of {expr} +sinh({expr}) Float hyperbolic sine of {expr} +sort({list} [, {func} [, {dict}]]) List sort {list}, using {func} to compare -soundfold( {word}) String sound-fold {word} +soundfold({word}) String sound-fold {word} spellbadword() String badly spelled word at cursor -spellsuggest( {word} [, {max} [, {capital}]]) +spellsuggest({word} [, {max} [, {capital}]]) List spelling suggestions -split( {expr} [, {pat} [, {keepempty}]]) +split({expr} [, {pat} [, {keepempty}]]) List make |List| from {pat} separated {expr} -sqrt( {expr}) Float square root of {expr} -str2float( {expr}) Float convert String to Float -str2nr( {expr} [, {base}]) Number convert String to Number -strchars( {expr} [, {skipcc}]) Number character length of the String {expr} -strdisplaywidth( {expr} [, {col}]) Number display length of the String {expr} -strftime( {format}[, {time}]) String time in specified format -stridx( {haystack}, {needle}[, {start}]) +sqrt({expr}) Float square root of {expr} +str2float({expr}) Float convert String to Float +str2nr({expr} [, {base}]) Number convert String to Number +strchars({expr} [, {skipcc}]) Number character length of the String {expr} +strdisplaywidth({expr} [, {col}]) Number display length of the String {expr} +strftime({format}[, {time}]) String time in specified format +stridx({haystack}, {needle}[, {start}]) Number index of {needle} in {haystack} -string( {expr}) String String representation of {expr} value -strlen( {expr}) Number length of the String {expr} -strpart( {src}, {start}[, {len}]) +string({expr}) String String representation of {expr} value +strlen({expr}) Number length of the String {expr} +strpart({src}, {start}[, {len}]) String {len} characters of {src} at {start} -strridx( {haystack}, {needle} [, {start}]) +strridx({haystack}, {needle} [, {start}]) Number last index of {needle} in {haystack} -strtrans( {expr}) String translate string to make it printable -strwidth( {expr}) Number display cell length of the String {expr} -submatch( {nr}[, {list}]) String or List +strtrans({expr}) String translate string to make it printable +strwidth({expr}) Number display cell length of the String {expr} +submatch({nr}[, {list}]) String or List specific match in ":s" or substitute() -substitute( {expr}, {pat}, {sub}, {flags}) +substitute({expr}, {pat}, {sub}, {flags}) String all {pat} in {expr} replaced with {sub} -synID( {lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col} -synIDattr( {synID}, {what} [, {mode}]) +synID({lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col} +synIDattr({synID}, {what} [, {mode}]) String attribute {what} of syntax ID {synID} -synIDtrans( {synID}) Number translated syntax ID of {synID} -synconcealed( {lnum}, {col}) List info about concealing -synstack( {lnum}, {col}) List stack of syntax IDs at {lnum} and {col} -system( {expr} [, {input}]) String output of shell command/filter {expr} -systemlist( {expr} [, {input}]) List output of shell command/filter {expr} -tabpagebuflist( [{arg}]) List list of buffer numbers in tab page -tabpagenr( [{arg}]) Number number of current or last tab page -tabpagewinnr( {tabarg}[, {arg}]) - Number number of current window in tab page -taglist( {expr}) List list of tags matching {expr} +synIDtrans({synID}) Number translated syntax ID of {synID} +synconcealed({lnum}, {col}) List info about concealing +synstack({lnum}, {col}) List stack of syntax IDs at {lnum} and {col} +system({expr} [, {input}]) String output of shell command/filter {expr} +systemlist({expr} [, {input}]) List output of shell command/filter {expr} +tabpagebuflist([{arg}]) List list of buffer numbers in tab page +tabpagenr([{arg}]) Number number of current or last tab page +tabpagewinnr({tabarg}[, {arg}]) Number number of current window in tab page +taglist({expr}) List list of tags matching {expr} tagfiles() List tags files used -tan( {expr}) Float tangent of {expr} -tanh( {expr}) Float hyperbolic tangent of {expr} +tan({expr}) Float tangent of {expr} +tanh({expr}) Float hyperbolic tangent of {expr} tempname() String name for a temporary file -timer_start( {time}, {callback} [, {options}]) +timer_start({time}, {callback} [, {options}]) Number create a timer -timer_stop( {timer}) none stop a timer -tolower( {expr}) String the String {expr} switched to lowercase -toupper( {expr}) String the String {expr} switched to uppercase -tr( {src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr} +timer_stop({timer}) none stop a timer +tolower({expr}) String the String {expr} switched to lowercase +toupper({expr}) String the String {expr} switched to uppercase +tr({src}, {fromstr}, {tostr}) String translate chars of {src} in {fromstr} to chars in {tostr} -trunc( {expr}) Float truncate Float {expr} -type( {name}) Number type of variable {name} -undofile( {name}) String undo file name for {name} +trunc({expr}) Float truncate Float {expr} +type({name}) Number type of variable {name} +undofile({name}) String undo file name for {name} undotree() List undo file tree -uniq( {list} [, {func} [, {dict}]]) +uniq({list} [, {func} [, {dict}]]) List remove adjacent duplicates from a list -values( {dict}) List values in {dict} -virtcol( {expr}) Number screen column of cursor or mark -visualmode( [expr]) String last visual mode used +values({dict}) List values in {dict} +virtcol({expr}) Number screen column of cursor or mark +visualmode([expr]) String last visual mode used wildmenumode() Number whether 'wildmenu' mode is active -win_findbuf( {bufnr}) List find windows containing {bufnr} -win_getid( [{win} [, {tab}]]) Number get window ID for {win} in {tab} -win_gotoid( {expr}) Number go to window with ID {expr} -win_id2tabwin( {expr}) List get tab and window nr from window ID -win_id2win( {expr}) Number get window nr from window ID -winbufnr( {nr}) Number buffer number of window {nr} +win_findbuf({bufnr}) List find windows containing {bufnr} +win_getid([{win} [, {tab}]]) Number get window ID for {win} in {tab} +win_gotoid({expr}) Number go to window with ID {expr} +win_id2tabwin({expr}) List get tab and window nr from window ID +win_id2win({expr}) Number get window nr from window ID +winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor -winheight( {nr}) Number height of window {nr} +winheight({nr}) Number height of window {nr} winline() Number window line of the cursor -winnr( [{expr}]) Number number of current window +winnr([{expr}]) Number number of current window winrestcmd() String returns command to restore window sizes -winrestview( {dict}) none restore view of current window +winrestview({dict}) none restore view of current window winsaveview() Dict save view of current window -winwidth( {nr}) Number width of window {nr} +winwidth({nr}) Number width of window {nr} wordcount() Dict get byte/char/word statistics -writefile( {list}, {fname} [, {flags}]) +writefile({list}, {fname} [, {flags}]) Number write list of lines to file {fname} -xor( {expr}, {expr}) Number bitwise XOR +xor({expr}, {expr}) Number bitwise XOR abs({expr}) *abs()* @@ -3674,19 +3684,27 @@ function({name} [, {arglist}] [, {dict}]) garbagecollect([{atexit}]) *garbagecollect()* - Cleanup unused |Lists| and |Dictionaries| that have circular - references. There is hardly ever a need to invoke this - function, as it is automatically done when Vim runs out of - memory or is waiting for the user to press a key after - 'updatetime'. Items without circular references are always - freed when they become unused. + Cleanup unused |Lists|, |Dictionaries|, |Channels| and |Jobs| + that have circular references. + + There is hardly ever a need to invoke this function, as it is + automatically done when Vim runs out of memory or is waiting + for the user to press a key after 'updatetime'. Items without + circular references are always freed when they become unused. This is useful if you have deleted a very big |List| and/or |Dictionary| with circular references in a script that runs for a long time. + When the optional {atexit} argument is one, garbage collection will also be done when exiting Vim, if it wasn't done before. This is useful when checking for memory leaks. +garbagecollect_for_testing() *garbagecollect_for_testing()* + Like garbagecollect(), but executed right away. This must + only be called directly to avoid any structure to exist + internally, and |v:testing| must have been set before calling + any function. + get({list}, {idx} [, {default}]) *get()* Get item {idx} from |List| {list}. When this item is not available return {default}. Return zero when {default} is @@ -4742,9 +4760,9 @@ json_encode({expr}) *json_encode()* String in double quotes (possibly null) Funcref not possible, error List as an array (possibly null); when - used recursively: [] + used recursively: [] Dict as an object (possibly null); when - used recursively: {} + used recursively: {} v:false "false" v:true "true" v:none "null" @@ -6086,7 +6104,7 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *searchpos()* < In this example "submatch" is 2 when a lowercase letter is found |/\l|, 3 when an uppercase letter is found |/\u|. -server2client( {clientid}, {string}) *server2client()* +server2client({clientid}, {string}) *server2client()* Send a reply string to {clientid}. The most recent {clientid} that sent a string can be retrieved with expand(""). {only available when compiled with the |+clientserver| feature} @@ -6599,7 +6617,7 @@ sqrt({expr}) *sqrt()* {only available when compiled with the |+float| feature} -str2float( {expr}) *str2float()* +str2float({expr}) *str2float()* Convert String {expr} to a Float. This mostly works the same as when using a floating point number in an expression, see |floating-point-format|. But it's a bit more permissive. @@ -6614,7 +6632,7 @@ str2float( {expr}) *str2float()* < {only available when compiled with the |+float| feature} -str2nr( {expr} [, {base}]) *str2nr()* +str2nr({expr} [, {base}]) *str2nr()* Convert string {expr} to a number. {base} is the conversion base, it can be 2, 8, 10 or 16. When {base} is omitted base 10 is used. This also means that @@ -7124,7 +7142,7 @@ timer_start({time}, {callback} [, {options}]) {options} is a dictionary. Supported entries: "repeat" Number of times to repeat calling the - callback. -1 means forever. + callback. -1 means forever. Example: > func MyHandler(timer) diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt index 4f79c575b3..3d91814b4f 100644 --- a/runtime/doc/if_pyth.txt +++ b/runtime/doc/if_pyth.txt @@ -653,10 +653,25 @@ vim.List object *python-List* class List(vim.List): # Subclassing vim.Function object *python-Function* - Function-like object, acting like vim |Funcref| object. Supports `.name` - attribute and is callable. Accepts special keyword argument `self`, see - |Dictionary-function|. You can also use `vim.Function(name)` constructor, - it is the same as `vim.bindeval('function(%s)'%json.dumps(name))`. + Function-like object, acting like vim |Funcref| object. Accepts special + keyword argument `self`, see |Dictionary-function|. You can also use + `vim.Function(name)` constructor, it is the same as + `vim.bindeval('function(%s)'%json.dumps(name))`. + + Attributes (read-only): + Attribute Description ~ + name Function name. + args `None` or a |python-List| object with arguments. Note that + this is a copy of the arguments list, constructed each time + you request this attribute. Modifications made to the list + will be ignored (but not to the containers inside argument + list: this is like |copy()| and not |deepcopy()|). + self `None` or a |python-Dictionary| object with self + dictionary. Note that explicit `self` keyword used when + calling resulting object overrides this attribute. + + Constructor additionally accepts `args` and `self` keywords. If any of + them is given then it constructs a partial, see |function()|. Examples: > f = vim.Function('tr') # Constructor @@ -670,6 +685,11 @@ vim.Function object *python-Function* print f(self={}) # Like call('DictFun', [], {}) print isinstance(f, vim.Function) # True + p = vim.Function('DictFun', self={}) + print f() + p = vim.Function('tr', args=['abc', 'a']) + print f('b') + ============================================================================== 8. pyeval() and py3eval() Vim functions *python-pyeval* diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt index 56745f3967..d41915e007 100644 --- a/runtime/doc/message.txt +++ b/runtime/doc/message.txt @@ -1,4 +1,4 @@ -*message.txt* For Vim version 7.4. Last change: 2016 Feb 27 +*message.txt* For Vim version 7.4. Last change: 2016 Apr 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -19,6 +19,15 @@ The ":messages" command can be used to view previously given messages. This is especially useful when messages have been overwritten or truncated. This depends on the 'shortmess' option. + :messages Show all messages. + + :{count}messages Show the {count} most recent messages. + + :messages clear Clear all messages. + + :{count}messages clear Clear messages, keeping only the {count} most + recent ones. + The number of remembered messages is fixed at 20 for the tiny version and 200 for other versions. @@ -58,8 +67,9 @@ If you are lazy, it also works without the shift key: > When an error message is displayed, but it is removed before you could read it, you can see it again with: > :echo errmsg -or view a list of recent messages with: > +Or view a list of recent messages with: > :messages +See `:messages` above. LIST OF MESSAGES diff --git a/src/Makefile b/src/Makefile index 002ce577e5..687c115941 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2015,23 +2015,25 @@ test1 \ test70 test71 test72 test73 test74 test75 test76 test77 test78 test79 \ test80 test81 test82 test83 test84 test85 test86 test87 test88 test89 \ test90 test91 test92 test93 test94 test95 test97 test98 test99 \ - test100 test101 test102 test103 test104 test105 test107 test108: + test100 test101 test102 test103 test104 test107 test108: cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) # Run individual NEW style test, assuming that Vim was already compiled. test_arglist \ test_assert \ test_assign \ + test_autocmd \ test_backspace_opt \ test_cdo \ test_channel \ test_cursor_func \ test_delete \ test_ex_undo \ - test_expr \ test_expand \ + test_expr \ test_feedkeys \ test_file_perm \ + test_fnamemodify \ test_glob2regpat \ test_hardcopy \ test_help_tagjump \ @@ -2041,17 +2043,22 @@ test_arglist \ test_json \ test_langmap \ test_lispwords \ + test_matchstrpos \ test_menu \ test_packadd \ test_partial \ test_perl \ test_quickfix \ + test_regexp_latin \ + test_regexp_utf8 \ test_reltime \ test_searchpos \ test_set \ test_sort \ + test_statusline \ test_syn_attr \ test_syntax \ + test_tabline \ test_timers \ test_undolevels \ test_unlet \ @@ -2059,6 +2066,8 @@ test_arglist \ test_viml \ test_visual \ test_window_id \ + test_alot_latin \ + test_alot_utf8 \ test_alot: cd testdir; rm -f $@.res test.log messages; $(MAKE) -f Makefile $@.res VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) @if test -f testdir/test.log; then \ @@ -2143,9 +2152,11 @@ installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \ # Generate the help tags with ":helptags" to handle all languages. # Move the distributed tags file aside and restore it, to avoid it being # different from the repository. - cd $(HELPSOURCE); if test -f tags; then mv -f tags tags.dist; fi + cd $(HELPSOURCE); if test -z "$(CROSS_COMPILING)" -a -f tags; then \ + mv -f tags tags.dist; fi @echo generating help tags - -@cd $(HELPSOURCE); $(MAKE) VIMEXE=$(DEST_BIN)/$(VIMTARGET) vimtags + -@cd $(HELPSOURCE); if test -z "$(CROSS_COMPILING)"; then \ + $(MAKE) VIMEXE=$(DEST_BIN)/$(VIMTARGET) vimtags; fi cd $(HELPSOURCE); \ files=`ls *.txt tags`; \ files="$$files `ls *.??x tags-?? 2>/dev/null || true`"; \ diff --git a/src/auto/configure b/src/auto/configure index f45a79121d..52348ad9e0 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -723,6 +723,7 @@ OS_EXTRA_OBJ OS_EXTRA_SRC XCODE_SELECT CPP_MM +CROSS_COMPILING STRIP AWK FGREP @@ -4123,11 +4124,14 @@ else $as_echo "no" >&6; } fi +CROSS_COMPILING= if test "$cross_compiling" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot compile a simple program; if not cross compiling check CC and CFLAGS" >&5 $as_echo "cannot compile a simple program; if not cross compiling check CC and CFLAGS" >&6; } + CROSS_COMPILING=1 fi + test "$GCC" = yes && CPP_MM=M; if test -f ./toolcheck; then diff --git a/src/channel.c b/src/channel.c index 042be7191b..3664e525ba 100644 --- a/src/channel.c +++ b/src/channel.c @@ -461,8 +461,7 @@ free_unused_channels(int copyID, int mask) ch_next = ch->ch_next; if ((ch->ch_copyID & mask) != (copyID & mask)) { - /* Free the channel and ordinary items it contains, but don't - * recurse into Lists, Dictionaries etc. */ + /* Free the channel struct itself. */ channel_free_channel(ch); } } @@ -4025,6 +4024,17 @@ job_free(job_T *job) } } +/* + * Return TRUE if the job should not be freed yet. Do not free the job when + * it has not ended yet and there is a "stoponexit" flag or an exit callback. + */ + static int +job_still_useful(job_T *job) +{ + return job->jv_status == JOB_STARTED + && (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL); +} + void job_unref(job_T *job) { @@ -4032,8 +4042,7 @@ job_unref(job_T *job) { /* Do not free the job when it has not ended yet and there is a * "stoponexit" flag or an exit callback. */ - if (job->jv_status != JOB_STARTED - || (job->jv_stoponexit == NULL && job->jv_exit_cb == NULL)) + if (!job_still_useful(job)) { job_free(job); } @@ -4055,7 +4064,8 @@ free_unused_jobs_contents(int copyID, int mask) job_T *job; for (job = first_job; job != NULL; job = job->jv_next) - if ((job->jv_copyID & mask) != (copyID & mask)) + if ((job->jv_copyID & mask) != (copyID & mask) + && !job_still_useful(job)) { /* Free the channel and ordinary items it contains, but don't * recurse into Lists, Dictionaries etc. */ @@ -4074,10 +4084,10 @@ free_unused_jobs(int copyID, int mask) for (job = first_job; job != NULL; job = job_next) { job_next = job->jv_next; - if ((job->jv_copyID & mask) != (copyID & mask)) + if ((job->jv_copyID & mask) != (copyID & mask) + && !job_still_useful(job)) { - /* Free the channel and ordinary items it contains, but don't - * recurse into Lists, Dictionaries etc. */ + /* Free the job struct itself. */ job_free_job(job); } } diff --git a/src/config.mk.in b/src/config.mk.in index c756da4f36..a53834c96b 100644 --- a/src/config.mk.in +++ b/src/config.mk.in @@ -106,6 +106,7 @@ AWK = @AWK@ STRIP = @STRIP@ EXEEXT = @EXEEXT@ +CROSS_COMPILING = @CROSS_COMPILING@ COMPILEDBY = @compiledby@ diff --git a/src/configure.in b/src/configure.in index 167653f310..436c5fb10b 100644 --- a/src/configure.in +++ b/src/configure.in @@ -88,9 +88,12 @@ fi dnl If configure thinks we are cross compiling, there might be something dnl wrong with the CC or CFLAGS settings, give a useful warning message +CROSS_COMPILING= if test "$cross_compiling" = yes; then AC_MSG_RESULT([cannot compile a simple program; if not cross compiling check CC and CFLAGS]) + CROSS_COMPILING=1 fi +AC_SUBST(CROSS_COMPILING) dnl gcc-cpp has the wonderful -MM option to produce nicer dependencies. dnl But gcc 3.1 changed the meaning! See near the end. diff --git a/src/edit.c b/src/edit.c index 9bd0a03f67..4abb11c73a 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1433,8 +1433,10 @@ doESCkey: docomplete: compl_busy = TRUE; + disable_fold_update++; /* don't redraw folds here */ if (ins_complete(c, TRUE) == FAIL) compl_cont_status = 0; + disable_fold_update--; compl_busy = FALSE; break; #endif /* FEAT_INS_EXPAND */ diff --git a/src/eval.c b/src/eval.c index 999e7f3c7c..46c806cdb7 100644 --- a/src/eval.c +++ b/src/eval.c @@ -373,6 +373,7 @@ static struct vimvar {VV_NAME("null", VAR_SPECIAL), VV_RO}, {VV_NAME("none", VAR_SPECIAL), VV_RO}, {VV_NAME("vim_did_enter", VAR_NUMBER), VV_RO}, + {VV_NAME("testing", VAR_NUMBER), 0}, }; /* shorthand */ @@ -452,7 +453,6 @@ static long dict_len(dict_T *d); static char_u *dict2string(typval_T *tv, int copyID); static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate); static char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); -static char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); static char_u *string_quote(char_u *str, int function); static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); static int find_internal_func(char_u *name); @@ -580,6 +580,7 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv); static void f_foreground(typval_T *argvars, typval_T *rettv); static void f_function(typval_T *argvars, typval_T *rettv); static void f_garbagecollect(typval_T *argvars, typval_T *rettv); +static void f_garbagecollect_for_testing(typval_T *argvars, typval_T *rettv); static void f_get(typval_T *argvars, typval_T *rettv); static void f_getbufline(typval_T *argvars, typval_T *rettv); static void f_getbufvar(typval_T *argvars, typval_T *rettv); @@ -777,9 +778,11 @@ static void f_strchars(typval_T *argvars, typval_T *rettv); #ifdef HAVE_STRFTIME static void f_strftime(typval_T *argvars, typval_T *rettv); #endif +static void f_strgetchar(typval_T *argvars, typval_T *rettv); static void f_stridx(typval_T *argvars, typval_T *rettv); static void f_string(typval_T *argvars, typval_T *rettv); static void f_strlen(typval_T *argvars, typval_T *rettv); +static void f_strcharpart(typval_T *argvars, typval_T *rettv); static void f_strpart(typval_T *argvars, typval_T *rettv); static void f_strridx(typval_T *argvars, typval_T *rettv); static void f_strtrans(typval_T *argvars, typval_T *rettv); @@ -1029,7 +1032,7 @@ eval_clear(void) ga_clear(&ga_scripts); /* unreferenced lists and dicts */ - (void)garbage_collect(); + (void)garbage_collect(FALSE); /* functions */ free_all_functions(); @@ -6889,6 +6892,9 @@ get_copyID(void) return current_copyID; } +/* Used by get_func_tv() */ +static garray_T funcargs = GA_EMPTY; + /* * Garbage collection for lists and dictionaries. * @@ -6911,10 +6917,11 @@ get_copyID(void) /* * Do garbage collection for lists and dicts. + * When "testing" is TRUE this is called from garbagecollect_for_testing(). * Return TRUE if some memory was freed. */ int -garbage_collect(void) +garbage_collect(int testing) { int copyID; int abort = FALSE; @@ -6928,10 +6935,13 @@ garbage_collect(void) tabpage_T *tp; #endif - /* Only do this once. */ - want_garbage_collect = FALSE; - may_garbage_collect = FALSE; - garbage_collect_at_exit = FALSE; + if (!testing) + { + /* Only do this once. */ + want_garbage_collect = FALSE; + may_garbage_collect = FALSE; + garbage_collect_at_exit = FALSE; + } /* We advance by two because we add one for items referenced through * previous_funccal. */ @@ -6989,6 +6999,11 @@ garbage_collect(void) abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL); } + /* function call arguments, if v:testing is set. */ + for (i = 0; i < funcargs.ga_len; ++i) + abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i], + copyID, NULL, NULL); + /* v: vars */ abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL); @@ -7034,7 +7049,7 @@ garbage_collect(void) if (did_free_funccal) /* When a funccal was freed some more items might be garbage * collected, so run again. */ - (void)garbage_collect(); + (void)garbage_collect(testing); } else if (p_verbose > 0) { @@ -8137,7 +8152,7 @@ echo_string( * Puts quotes around strings, so that they can be parsed back by eval(). * May return NULL. */ - static char_u * + char_u * tv2string( typval_T *tv, char_u **tofree, @@ -8424,6 +8439,7 @@ static struct fst {"foreground", 0, 0, f_foreground}, {"function", 1, 3, f_function}, {"garbagecollect", 0, 1, f_garbagecollect}, + {"garbagecollect_for_testing", 0, 0, f_garbagecollect_for_testing}, {"get", 2, 3, f_get}, {"getbufline", 2, 3, f_getbufline}, {"getbufvar", 2, 3, f_getbufvar}, @@ -8620,11 +8636,13 @@ static struct fst {"str2float", 1, 1, f_str2float}, #endif {"str2nr", 1, 2, f_str2nr}, + {"strcharpart", 2, 3, f_strcharpart}, {"strchars", 1, 2, f_strchars}, {"strdisplaywidth", 1, 2, f_strdisplaywidth}, #ifdef HAVE_STRFTIME {"strftime", 1, 2, f_strftime}, #endif + {"strgetchar", 2, 2, f_strgetchar}, {"stridx", 2, 3, f_stridx}, {"string", 1, 1, f_string}, {"strlen", 1, 1, f_strlen}, @@ -8896,8 +8914,26 @@ get_func_tv( ret = FAIL; if (ret == OK) + { + int i = 0; + + if (get_vim_var_nr(VV_TESTING)) + { + /* Prepare for calling garbagecollect_for_testing(), need to know + * what variables are used on the call stack. */ + if (funcargs.ga_itemsize == 0) + ga_init2(&funcargs, (int)sizeof(typval_T *), 50); + for (i = 0; i < argcount; ++i) + if (ga_grow(&funcargs, 1) == OK) + ((typval_T **)funcargs.ga_data)[funcargs.ga_len++] = + &argvars[i]; + } + ret = call_func(name, len, rettv, argcount, argvars, firstline, lastline, doesrange, evaluate, partial, selfdict); + + funcargs.ga_len -= i; + } else if (!aborting()) { if (argcount == MAX_FUNC_ARGS) @@ -12317,6 +12353,17 @@ f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED) garbage_collect_at_exit = TRUE; } +/* + * "garbagecollect_for_testing()" function + */ + static void +f_garbagecollect_for_testing(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ + /* This is dangerous, any Lists and Dicts used internally may be freed + * while still in use. */ + garbage_collect(TRUE); +} + /* * "get()" function */ @@ -13008,26 +13055,6 @@ f_getpid(typval_T *argvars UNUSED, typval_T *rettv) rettv->vval.v_number = mch_get_pid(); } -static void getpos_both(typval_T *argvars, typval_T *rettv, int getcurpos); - -/* - * "getcurpos()" function - */ - static void -f_getcurpos(typval_T *argvars, typval_T *rettv) -{ - getpos_both(argvars, rettv, TRUE); -} - -/* - * "getpos(string)" function - */ - static void -f_getpos(typval_T *argvars, typval_T *rettv) -{ - getpos_both(argvars, rettv, FALSE); -} - static void getpos_both( typval_T *argvars, @@ -13070,6 +13097,25 @@ getpos_both( rettv->vval.v_number = FALSE; } + +/* + * "getcurpos()" function + */ + static void +f_getcurpos(typval_T *argvars, typval_T *rettv) +{ + getpos_both(argvars, rettv, TRUE); +} + +/* + * "getpos(string)" function + */ + static void +f_getpos(typval_T *argvars, typval_T *rettv) +{ + getpos_both(argvars, rettv, FALSE); +} + /* * "getqflist()" and "getloclist()" functions */ @@ -19533,6 +19579,46 @@ f_strftime(typval_T *argvars, typval_T *rettv) } #endif +/* + * "strgetchar()" function + */ + static void +f_strgetchar(typval_T *argvars, typval_T *rettv) +{ + char_u *str; + int len; + int error = FALSE; + int charidx; + + rettv->vval.v_number = -1; + str = get_tv_string_chk(&argvars[0]); + if (str == NULL) + return; + len = (int)STRLEN(str); + charidx = get_tv_number_chk(&argvars[1], &error); + if (error) + return; +#ifdef FEAT_MBYTE + { + int byteidx = 0; + + while (charidx >= 0 && byteidx < len) + { + if (charidx == 0) + { + rettv->vval.v_number = mb_ptr2char(str + byteidx); + break; + } + --charidx; + byteidx += mb_cptr2len(str + byteidx); + } + } +#else + if (charidx < len) + rettv->vval.v_number = str[charidx]; +#endif +} + /* * "stridx()" function */ @@ -19660,6 +19746,71 @@ f_strwidth(typval_T *argvars, typval_T *rettv) ); } +/* + * "strcharpart()" function + */ + static void +f_strcharpart(typval_T *argvars, typval_T *rettv) +{ +#ifdef FEAT_MBYTE + char_u *p; + int nchar; + int nbyte = 0; + int charlen; + int len = 0; + int slen; + int error = FALSE; + + p = get_tv_string(&argvars[0]); + slen = (int)STRLEN(p); + + nchar = get_tv_number_chk(&argvars[1], &error); + if (!error) + { + if (nchar > 0) + while (nchar > 0 && nbyte < slen) + { + nbyte += mb_char2len(p[nbyte]); + --nchar; + } + else + nbyte = nchar; + if (argvars[2].v_type != VAR_UNKNOWN) + { + charlen = get_tv_number(&argvars[2]); + while (charlen > 0 && nbyte + len < slen) + { + len += mb_char2len(p[nbyte + len]); + --charlen; + } + } + else + len = slen - nbyte; /* default: all bytes that are available. */ + } + + /* + * Only return the overlap between the specified part and the actual + * string. + */ + if (nbyte < 0) + { + len += nbyte; + nbyte = 0; + } + else if (nbyte > slen) + nbyte = slen; + if (len < 0) + len = 0; + else if (nbyte + len > slen) + len = slen - nbyte; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strnsave(p + nbyte, len); +#else + f_strpart(argvars, rettv); +#endif +} + /* * "strpart()" function */ diff --git a/src/ex_cmds.c b/src/ex_cmds.c index daac3ae8d6..d83dc405c7 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -6203,6 +6203,13 @@ find_help_tags( *d++ = *s; + /* + * If tag contains "({" or "([", tag terminates at the "(". + * This is for help on functions, e.g.: abs({expr}). + */ + if (*s == '(' && (s[1] == '{' || s[1] =='[')) + break; + /* * If tag starts with ', toss everything after a second '. Fixes * CTRL-] on 'option'. (would include the trailing '.'). diff --git a/src/ex_cmds.h b/src/ex_cmds.h index d2d90a2a27..9741ffdf77 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -66,6 +66,7 @@ #define ADDR_BUFFERS 4 #define ADDR_TABS 5 #define ADDR_QUICKFIX 6 +#define ADDR_OTHER 99 #ifndef DO_DECLARE_EXCMD typedef struct exarg exarg_T; @@ -892,8 +893,8 @@ EX(CMD_menutranslate, "menutranslate", ex_menutranslate, EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN, ADDR_LINES), EX(CMD_messages, "messages", ex_messages, - TRLBAR|CMDWIN, - ADDR_LINES), + EXTRA|TRLBAR|RANGE|CMDWIN, + ADDR_OTHER), EX(CMD_mkexrc, "mkexrc", ex_mkrc, BANG|FILE1|TRLBAR|CMDWIN, ADDR_LINES), diff --git a/src/fold.c b/src/fold.c index e0b2609d98..8b9ca35ebf 100644 --- a/src/fold.c +++ b/src/fold.c @@ -811,6 +811,9 @@ foldUpdate(win_T *wp, linenr_T top, linenr_T bot) { fold_T *fp; + if (disable_fold_update > 0) + return; + /* Mark all folds from top to bot as maybe-small. */ (void)foldFind(&wp->w_folds, top, &fp); while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len diff --git a/src/getchar.c b/src/getchar.c index 6b9340b180..58da5df12e 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -1523,7 +1523,7 @@ before_blocking(void) updatescript(0); #ifdef FEAT_EVAL if (may_garbage_collect) - garbage_collect(); + garbage_collect(FALSE); #endif } @@ -1571,7 +1571,7 @@ vgetc(void) /* Do garbage collection when garbagecollect() was called previously and * we are now at the toplevel. */ if (may_garbage_collect && want_garbage_collect) - garbage_collect(); + garbage_collect(FALSE); #endif /* diff --git a/src/globals.h b/src/globals.h index 122204ebaf..53c0253442 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1178,6 +1178,10 @@ EXTERN int fill_fold INIT(= '-'); EXTERN int fill_diff INIT(= '-'); #endif +#ifdef FEAT_FOLDING +EXTERN int disable_fold_update INIT(= 0); +#endif + /* Whether 'keymodel' contains "stopsel" and "startsel". */ EXTERN int km_stopsel INIT(= FALSE); EXTERN int km_startsel INIT(= FALSE); diff --git a/src/if_perl.xs b/src/if_perl.xs index 4fbc13e3a5..b091bf7cab 100644 --- a/src/if_perl.xs +++ b/src/if_perl.xs @@ -57,7 +57,9 @@ #include #include #include - +#if defined(PERLIO_LAYERS) && !defined(USE_SFIO) +# include +#endif /* * Work around clashes between Perl and Vim namespace. proto.h doesn't @@ -293,6 +295,10 @@ typedef int perl_key; # define Perl_av_fetch dll_Perl_av_fetch # define Perl_av_len dll_Perl_av_len # define Perl_sv_2nv_flags dll_Perl_sv_2nv_flags +# if defined(PERLIO_LAYERS) && !defined(USE_SFIO) +# define PerlIOBase_pushed dll_PerlIOBase_pushed +# define PerlIO_define_layer dll_PerlIO_define_layer +# endif /* * Declare HANDLE for perl.dll and function pointers. @@ -445,6 +451,10 @@ static SV * (*Perl_hv_iterval)(pTHX_ HV *, HE *); static SV** (*Perl_av_fetch)(pTHX_ AV *, SSize_t, I32); static SSize_t (*Perl_av_len)(pTHX_ AV *); static NV (*Perl_sv_2nv_flags)(pTHX_ SV *const, const I32); +#if defined(PERLIO_LAYERS) && !defined(USE_SFIO) +static IV (*PerlIOBase_pushed)(pTHX_ PerlIO *, const char *, SV *, PerlIO_funcs *); +static void (*PerlIO_define_layer)(pTHX_ PerlIO_funcs *); +#endif /* * Table of name to function pointer of perl. @@ -584,6 +594,10 @@ static struct { {"Perl_av_fetch", (PERL_PROC*)&Perl_av_fetch}, {"Perl_av_len", (PERL_PROC*)&Perl_av_len}, {"Perl_sv_2nv_flags", (PERL_PROC*)&Perl_sv_2nv_flags}, +#if defined(PERLIO_LAYERS) && !defined(USE_SFIO) + {"PerlIOBase_pushed", (PERL_PROC*)&PerlIOBase_pushed}, + {"PerlIO_define_layer", (PERL_PROC*)&PerlIO_define_layer}, +#endif {"", NULL}, }; @@ -646,6 +660,10 @@ perl_enabled(int verbose) } #endif /* DYNAMIC_PERL */ +#if defined(PERLIO_LAYERS) && !defined(USE_SFIO) +static void vim_IOLayer_init(void); +#endif + /* * perl_init(): initialize perl interpreter * We have to call perl_parse to initialize some structures, @@ -671,6 +689,8 @@ perl_init(void) sfdisc(PerlIO_stderr(), sfdcnewvim()); sfsetbuf(PerlIO_stdout(), NULL, 0); sfsetbuf(PerlIO_stderr(), NULL, 0); +#elif defined(PERLIO_LAYERS) + vim_IOLayer_init(); #endif } @@ -1307,6 +1327,82 @@ err: } } +#if defined(PERLIO_LAYERS) && !defined(USE_SFIO) +typedef struct { + struct _PerlIO base; + int attr; +} PerlIOVim; + + static IV +PerlIOVim_pushed(pTHX_ PerlIO *f, const char *mode, + SV *arg, PerlIO_funcs *tab) +{ + PerlIOVim *s = PerlIOSelf(f, PerlIOVim); + s->attr = 0; + if (arg && SvPOK(arg)) { + int id = syn_name2id((char_u *)SvPV_nolen(arg)); + if (id != 0) + s->attr = syn_id2attr(id); + } + return PerlIOBase_pushed(aTHX_ f, mode, (SV *)NULL, tab); +} + + static SSize_t +PerlIOVim_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) +{ + char_u *str; + PerlIOVim * s = PerlIOSelf(f, PerlIOVim); + + str = vim_strnsave((char_u *)vbuf, count); + if (str == NULL) + return 0; + msg_split((char_u *)str, s->attr); + vim_free(str); + + return count; +} + +static PERLIO_FUNCS_DECL(PerlIO_Vim) = { + sizeof(PerlIO_funcs), + "Vim", + sizeof(PerlIOVim), + PERLIO_K_DUMMY, /* flags */ + PerlIOVim_pushed, + NULL, /* popped */ + NULL, /* open */ + NULL, /* binmode */ + NULL, /* arg */ + NULL, /* fileno */ + NULL, /* dup */ + NULL, /* read */ + NULL, /* unread */ + PerlIOVim_write, + NULL, /* seek */ + NULL, /* tell */ + NULL, /* close */ + NULL, /* flush */ + NULL, /* fill */ + NULL, /* eof */ + NULL, /* error */ + NULL, /* clearerr */ + NULL, /* setlinebuf */ + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL /* set_ptrcnt */ +}; + +/* Use Vim routine for print operator */ + static void +vim_IOLayer_init(void) +{ + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_Vim)); + (void)eval_pv( "binmode(STDOUT, ':Vim')" + " && binmode(STDERR, ':Vim(ErrorMsg)');", 0); +} +#endif /* PERLIO_LAYERS && !USE_SFIO */ + #ifndef FEAT_WINDOWS int win_valid(win_T *w) diff --git a/src/if_py_both.h b/src/if_py_both.h index ee882600fc..0b701ae082 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -72,6 +72,7 @@ typedef void (*runner)(const char *, void * static int ConvertFromPyObject(PyObject *, typval_T *); static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *); static int ConvertFromPyMapping(PyObject *, typval_T *); +static int ConvertFromPySequence(PyObject *, typval_T *); static PyObject *WindowNew(win_T *, tabpage_T *); static PyObject *BufferNew (buf_T *); static PyObject *LineToString(const char *); @@ -1433,6 +1434,7 @@ typedef struct pylinkedlist_S { static pylinkedlist_T *lastdict = NULL; static pylinkedlist_T *lastlist = NULL; +static pylinkedlist_T *lastfunc = NULL; static void pyll_remove(pylinkedlist_T *ref, pylinkedlist_T **last) @@ -2828,14 +2830,20 @@ typedef struct { PyObject_HEAD char_u *name; + int argc; + typval_T *argv; + dict_T *self; + pylinkedlist_T ref; } FunctionObject; static PyTypeObject FunctionType; -#define NEW_FUNCTION(name) FunctionNew(&FunctionType, name) +#define NEW_FUNCTION(name, argc, argv, self) \ + FunctionNew(&FunctionType, name, argc, argv, self) static PyObject * -FunctionNew(PyTypeObject *subtype, char_u *name) +FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv, + dict_T *selfdict) { FunctionObject *self; @@ -2865,6 +2873,13 @@ FunctionNew(PyTypeObject *subtype, char_u *name) return NULL; } + self->argc = argc; + self->argv = argv; + self->self = selfdict; + + if (self->argv || self->self) + pyll_add((PyObject *)(self), &self->ref, &lastfunc); + return (PyObject *)(self); } @@ -2872,19 +2887,59 @@ FunctionNew(PyTypeObject *subtype, char_u *name) FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) { PyObject *self; + PyObject *selfdictObject; + PyObject *argsObject = NULL; char_u *name; + typval_T selfdicttv; + typval_T argstv; + list_T *argslist = NULL; + dict_T *selfdict = NULL; + int argc = 0; + typval_T *argv = NULL; + typval_T *curtv; + listitem_T *li; - if (kwargs) + if (kwargs != NULL) { - PyErr_SET_STRING(PyExc_TypeError, - N_("function constructor does not accept keyword arguments")); - return NULL; + selfdictObject = PyDict_GetItemString(kwargs, "self"); + if (selfdictObject != NULL) + { + if (ConvertFromPyMapping(selfdictObject, &selfdicttv) == -1) + return NULL; + selfdict = selfdicttv.vval.v_dict; + } + argsObject = PyDict_GetItemString(kwargs, "args"); + if (argsObject != NULL) + { + if (ConvertFromPySequence(argsObject, &argstv) == -1) + { + dict_unref(selfdict); + return NULL; + } + argslist = argstv.vval.v_list; + + argc = argslist->lv_len; + if (argc != 0) + { + argv = PyMem_New(typval_T, (size_t) argc); + curtv = argv; + for (li = argslist->lv_first; li != NULL; li = li->li_next) + copy_tv(&li->li_tv, curtv++); + } + list_unref(argslist); + } } if (!PyArg_ParseTuple(args, "et", "ascii", &name)) + { + dict_unref(selfdict); + while (argc--) + clear_tv(&argv[argc]); + PyMem_Free(argv); return NULL; + } - self = FunctionNew(subtype, name); + self = FunctionNew(subtype, name, argc, argv, selfdict); PyMem_Free(name); @@ -2894,14 +2949,21 @@ FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) static void FunctionDestructor(FunctionObject *self) { + int i; func_unref(self->name); vim_free(self->name); + for (i = 0; i < self->argc; ++i) + clear_tv(&self->argv[i]); + PyMem_Free(self->argv); + dict_unref(self->self); + if (self->argv || self->self) + pyll_remove(&self->ref, &lastfunc); DESTRUCTOR_FINISH(self); } static char *FunctionAttrs[] = { - "softspace", + "softspace", "args", "self", NULL }; @@ -2911,6 +2973,68 @@ FunctionDir(PyObject *self) return ObjectDir(self, FunctionAttrs); } + static PyObject * +FunctionAttr(FunctionObject *self, char *name) +{ + list_T *list; + int i; + if (strcmp(name, "name") == 0) + return PyString_FromString((char *)(self->name)); + else if (strcmp(name, "args") == 0) + { + if (self->argv == NULL) + return AlwaysNone(NULL); + list = list_alloc(); + for (i = 0; i < self->argc; ++i) + list_append_tv(list, &self->argv[i]); + return NEW_LIST(list); + } + else if (strcmp(name, "self") == 0) + return self->self == NULL + ? AlwaysNone(NULL) + : NEW_DICTIONARY(self->self); + else if (strcmp(name, "__members__") == 0) + return ObjectDir(NULL, FunctionAttrs); + return NULL; +} + +/* Populate partial_T given function object. + * + * "exported" should be set to true when it is needed to construct a partial + * that may be stored in a variable (i.e. may be freed by Vim). + */ + static void +set_partial(FunctionObject *self, partial_T *pt, int exported) +{ + int i; + + pt->pt_name = self->name; + if (self->argv) + { + pt->pt_argc = self->argc; + if (exported) + { + pt->pt_argv = (typval_T *)alloc_clear( + sizeof(typval_T) * self->argc); + for (i = 0; i < pt->pt_argc; ++i) + copy_tv(&self->argv[i], &pt->pt_argv[i]); + } + else + pt->pt_argv = self->argv; + } + else + { + pt->pt_argc = 0; + pt->pt_argv = NULL; + } + pt->pt_dict = self->self; + if (exported && self->self) + ++pt->pt_dict->dv_refcount; + if (exported) + pt->pt_name = vim_strsave(pt->pt_name); + pt->pt_refcount = 1; +} + static PyObject * FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs) { @@ -2922,8 +3046,10 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs) PyObject *selfdictObject; PyObject *ret; int error; + partial_T pt; + partial_T *pt_ptr = NULL; - if (ConvertFromPyObject(argsObject, &args) == -1) + if (ConvertFromPySequence(argsObject, &args) == -1) return NULL; if (kwargs != NULL) @@ -2940,11 +3066,17 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs) } } + if (self->argv || self->self) + { + set_partial(self, &pt, FALSE); + pt_ptr = &pt; + } + Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); VimTryStart(); - error = func_call(name, &args, NULL, selfdict, &rettv); + error = func_call(name, &args, pt_ptr, selfdict, &rettv); Python_Release_Vim(); Py_END_ALLOW_THREADS @@ -2970,14 +3102,49 @@ FunctionCall(FunctionObject *self, PyObject *argsObject, PyObject *kwargs) static PyObject * FunctionRepr(FunctionObject *self) { -#ifdef Py_TRACE_REFS - /* For unknown reason self->name may be NULL after calling - * Finalize */ - return PyString_FromFormat("", - (self->name == NULL ? "" : (char *)self->name)); -#else - return PyString_FromFormat("", (char *)self->name); -#endif + PyObject *ret; + garray_T repr_ga; + int i; + char_u *tofree = NULL; + typval_T tv; + char_u numbuf[NUMBUFLEN]; + + ga_init2(&repr_ga, (int)sizeof(char), 70); + ga_concat(&repr_ga, (char_u *)"name) + ga_concat(&repr_ga, self->name); + else + ga_concat(&repr_ga, (char_u *)""); + ga_append(&repr_ga, '\''); + if (self->argv) + { + ga_concat(&repr_ga, (char_u *)", args=["); + ++emsg_silent; + for (i = 0; i < self->argc; i++) + { + if (i != 0) + ga_concat(&repr_ga, (char_u *)", "); + ga_concat(&repr_ga, tv2string(&self->argv[i], &tofree, numbuf, + get_copyID())); + vim_free(tofree); + } + --emsg_silent; + ga_append(&repr_ga, ']'); + } + if (self->self) + { + ga_concat(&repr_ga, (char_u *)", self="); + tv.v_type = VAR_DICT; + tv.vval.v_dict = self->self; + ++emsg_silent; + ga_concat(&repr_ga, tv2string(&tv, &tofree, numbuf, get_copyID())); + --emsg_silent; + vim_free(tofree); + } + ga_append(&repr_ga, '>'); + ret = PyString_FromString((char *)repr_ga.ga_data); + ga_clear(&repr_ga); + return ret; } static struct PyMethodDef FunctionMethods[] = { @@ -5551,11 +5718,13 @@ set_ref_in_py(const int copyID) pylinkedlist_T *cur; dict_T *dd; list_T *ll; + int i; int abort = FALSE; + FunctionObject *func; if (lastdict != NULL) { - for(cur = lastdict ; !abort && cur != NULL ; cur = cur->pll_prev) + for (cur = lastdict ; !abort && cur != NULL ; cur = cur->pll_prev) { dd = ((DictionaryObject *) (cur->pll_obj))->dict; if (dd->dv_copyID != copyID) @@ -5568,7 +5737,7 @@ set_ref_in_py(const int copyID) if (lastlist != NULL) { - for(cur = lastlist ; !abort && cur != NULL ; cur = cur->pll_prev) + for (cur = lastlist ; !abort && cur != NULL ; cur = cur->pll_prev) { ll = ((ListObject *) (cur->pll_obj))->list; if (ll->lv_copyID != copyID) @@ -5579,6 +5748,24 @@ set_ref_in_py(const int copyID) } } + if (lastfunc != NULL) + { + for (cur = lastfunc ; !abort && cur != NULL ; cur = cur->pll_prev) + { + func = (FunctionObject *) cur->pll_obj; + if (func->self != NULL && func->self->dv_copyID != copyID) + { + func->self->dv_copyID = copyID; + abort = abort || set_ref_in_ht( + &func->self->dv_hashtab, copyID, NULL); + } + if (func->argc) + for (i = 0; !abort && i < func->argc; ++i) + abort = abort + || set_ref_in_item(&func->argv[i], copyID, NULL, NULL); + } + } + return abort; } @@ -5879,6 +6066,34 @@ ConvertFromPyMapping(PyObject *obj, typval_T *tv) return ret; } + static int +ConvertFromPySequence(PyObject *obj, typval_T *tv) +{ + PyObject *lookup_dict; + int ret = 0; + + if (!(lookup_dict = PyDict_New())) + return -1; + + if (PyType_IsSubtype(obj->ob_type, &ListType)) + { + tv->v_type = VAR_LIST; + tv->vval.v_list = (((ListObject *)(obj))->list); + ++tv->vval.v_list->lv_refcount; + } + else if (PyIter_Check(obj) || PySequence_Check(obj)) + return convert_dl(obj, tv, pyseq_to_tv, lookup_dict); + else + { + PyErr_FORMAT(PyExc_TypeError, + N_("unable to convert %s to vim list"), + Py_TYPE_NAME(obj)); + ret = -1; + } + Py_DECREF(lookup_dict); + return ret; +} + static int ConvertFromPyObject(PyObject *obj, typval_T *tv) { @@ -5909,11 +6124,22 @@ _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict) } else if (PyType_IsSubtype(obj->ob_type, &FunctionType)) { - if (set_string_copy(((FunctionObject *) (obj))->name, tv) == -1) - return -1; + FunctionObject *func = (FunctionObject *) obj; + if (func->self != NULL || func->argv != NULL) + { + partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); + set_partial(func, pt, TRUE); + tv->vval.v_partial = pt; + tv->v_type = VAR_PARTIAL; + } + else + { + if (set_string_copy(func->name, tv) == -1) + return -1; - tv->v_type = VAR_FUNC; - func_ref(tv->vval.v_string); + tv->v_type = VAR_FUNC; + } + func_ref(func->name); } else if (PyBytes_Check(obj)) { @@ -6009,6 +6235,8 @@ _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict) static PyObject * ConvertToPyObject(typval_T *tv) { + typval_T *argv; + int i; if (tv == NULL) { PyErr_SET_VIM(N_("internal error: NULL reference passed")); @@ -6031,10 +6259,23 @@ ConvertToPyObject(typval_T *tv) return NEW_DICTIONARY(tv->vval.v_dict); case VAR_FUNC: return NEW_FUNCTION(tv->vval.v_string == NULL - ? (char_u *)"" : tv->vval.v_string); + ? (char_u *)"" : tv->vval.v_string, + 0, NULL, NULL); case VAR_PARTIAL: + if (tv->vval.v_partial->pt_argc) + { + argv = PyMem_New(typval_T, (size_t)tv->vval.v_partial->pt_argc); + for (i = 0; i < tv->vval.v_partial->pt_argc; i++) + copy_tv(&tv->vval.v_partial->pt_argv[i], &argv[i]); + } + else + argv = NULL; + if (tv->vval.v_partial->pt_dict != NULL) + tv->vval.v_partial->pt_dict->dv_refcount++; return NEW_FUNCTION(tv->vval.v_partial == NULL - ? (char_u *)"" : tv->vval.v_partial->pt_name); + ? (char_u *)"" : tv->vval.v_partial->pt_name, + tv->vval.v_partial->pt_argc, argv, + tv->vval.v_partial->pt_dict); case VAR_UNKNOWN: case VAR_CHANNEL: case VAR_JOB: diff --git a/src/if_python.c b/src/if_python.c index 28ba4634d7..cce997ac13 100644 --- a/src/if_python.c +++ b/src/if_python.c @@ -1543,12 +1543,12 @@ ListGetattr(PyObject *self, char *name) static PyObject * FunctionGetattr(PyObject *self, char *name) { - FunctionObject *this = (FunctionObject *)(self); + PyObject *r; - if (strcmp(name, "name") == 0) - return PyString_FromString((char *)(this->name)); - else if (strcmp(name, "__members__") == 0) - return ObjectDir(NULL, FunctionAttrs); + r = FunctionAttr((FunctionObject *)(self), name); + + if (r || PyErr_Occurred()) + return r; else return Py_FindMethod(FunctionMethods, self, name); } diff --git a/src/if_python3.c b/src/if_python3.c index 5cf508fc71..d2f6066cb8 100644 --- a/src/if_python3.c +++ b/src/if_python3.c @@ -1528,14 +1528,16 @@ ListSetattro(PyObject *self, PyObject *nameobj, PyObject *val) static PyObject * FunctionGetattro(PyObject *self, PyObject *nameobj) { + PyObject *r; FunctionObject *this = (FunctionObject *)(self); GET_ATTR_STRING(name, nameobj); - if (strcmp(name, "name") == 0) - return PyUnicode_FromString((char *)(this->name)); - - return PyObject_GenericGetAttr(self, nameobj); + r = FunctionAttr(this, name); + if (r || PyErr_Occurred()) + return r; + else + return PyObject_GenericGetAttr(self, nameobj); } /* External interface diff --git a/src/main.c b/src/main.c index b3a593cd1b..dd4604b9e9 100644 --- a/src/main.c +++ b/src/main.c @@ -1603,7 +1603,7 @@ getout(int exitval) #endif #ifdef FEAT_EVAL if (garbage_collect_at_exit) - garbage_collect(); + garbage_collect(FALSE); #endif #if defined(WIN32) && defined(FEAT_MBYTE) free_cmd_argsW(); diff --git a/src/message.c b/src/message.c index f40408706e..88c67853bd 100644 --- a/src/message.c +++ b/src/message.c @@ -766,20 +766,54 @@ delete_first_msg(void) * ":messages" command. */ void -ex_messages(exarg_T *eap UNUSED) +ex_messages(exarg_T *eap) { struct msg_hist *p; char_u *s; + int c = 0; + + if (STRCMP(eap->arg, "clear") == 0) + { + int keep = eap->addr_count == 0 ? 0 : eap->line2; + + while (msg_hist_len > keep) + (void)delete_first_msg(); + return; + } + + if (*eap->arg != NUL) + { + EMSG(_(e_invarg)); + return; + } msg_hist_off = TRUE; - s = mch_getenv((char_u *)"LANG"); - if (s != NULL && *s != NUL) - msg_attr((char_u *) - _("Messages maintainer: Bram Moolenaar "), - hl_attr(HLF_T)); + p = first_msg_hist; + if (eap->addr_count != 0) + { + /* Count total messages */ + for (; p != NULL && !got_int; p = p->next) + c++; - for (p = first_msg_hist; p != NULL && !got_int; p = p->next) + c -= eap->line2; + + /* Skip without number of messages specified */ + for (p = first_msg_hist; p != NULL && !got_int && c > 0; + p = p->next, c--); + } + + if (p == first_msg_hist) + { + s = mch_getenv((char_u *)"LANG"); + if (s != NULL && *s != NUL) + msg_attr((char_u *) + _("Messages maintainer: Bram Moolenaar "), + hl_attr(HLF_T)); + } + + /* Display what was not skipped. */ + for (; p != NULL && !got_int; p = p->next) if (p->msg != NULL) msg_attr(p->msg, p->attr); diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 38392b9bd2..60fad80634 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -49,7 +49,6 @@ void partial_unref(partial_T *pt); list_T *list_alloc(void); int rettv_list_alloc(typval_T *rettv); void list_unref(list_T *l); -void list_free_internal(list_T *l); void list_free(list_T *l); listitem_T *listitem_alloc(void); void listitem_free(listitem_T *item); @@ -66,14 +65,13 @@ int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item); void list_insert(list_T *l, listitem_T *ni, listitem_T *item); void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2); int get_copyID(void); -int garbage_collect(void); +int garbage_collect(int testing); int set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack); int set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack); int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack); dict_T *dict_alloc(void); int rettv_dict_alloc(typval_T *rettv); void dict_unref(dict_T *d); -void dict_free_internal(dict_T *d); void dict_free(dict_T *d); dictitem_T *dictitem_alloc(char_u *key); void dictitem_free(dictitem_T *item); @@ -152,4 +150,5 @@ void ex_oldfiles(exarg_T *eap); void reset_v_option_vars(void); int modify_fname(char_u *src, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen); char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags); +char_u *tv2string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); /* vim: set ft=c : */ diff --git a/src/screen.c b/src/screen.c index 7d2a1f3e00..cb4470d9bc 100644 --- a/src/screen.c +++ b/src/screen.c @@ -3057,8 +3057,8 @@ win_line( wrapping */ int vcol_off = 0; /* offset for concealed characters */ int did_wcol = FALSE; - int match_conc = FALSE; /* cchar for match functions */ - int has_match_conc = FALSE; /* match wants to conceal */ + int match_conc = 0; /* cchar for match functions */ + int has_match_conc = 0; /* match wants to conceal */ int old_boguscols = 0; # define VCOL_HLC (vcol - vcol_off) # define FIX_FOR_BOGUSCOLS \ @@ -3595,7 +3595,7 @@ win_line( for (;;) { #ifdef FEAT_CONCEAL - has_match_conc = FALSE; + has_match_conc = 0; #endif /* Skip this quickly when working on the text. */ if (draw_state != WL_LINE) @@ -3944,11 +3944,12 @@ win_line( if (cur != NULL && syn_name2id((char_u *)"Conceal") == cur->hlg_id) { - has_match_conc = TRUE; + has_match_conc = + v == (long)shl->startcol ? 2 : 1; match_conc = cur->conceal_char; } else - has_match_conc = match_conc = FALSE; + has_match_conc = match_conc = 0; #endif } else if (v == (long)shl->endcol) @@ -4905,12 +4906,12 @@ win_line( if ( wp->w_p_cole > 0 && (wp != curwin || lnum != wp->w_cursor.lnum || conceal_cursor_line(wp) ) - && ( (syntax_flags & HL_CONCEAL) != 0 || has_match_conc) + && ( (syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0) && !(lnum_in_visual_area && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { char_attr = conceal_attr; - if (prev_syntax_id != syntax_seqnr + if ((prev_syntax_id != syntax_seqnr || has_match_conc > 1) && (syn_get_sub_char() != NUL || match_conc || wp->w_p_cole == 1) && wp->w_p_cole != 3) diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 2540abfbf0..0e4ab7f523 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -104,7 +104,6 @@ SCRIPTS_ALL = \ test_listlbr.out \ test_mapping.out \ test_marks.out \ - test_match_conceal.out \ test_nested_function.out \ test_options.out \ test_ruby.out \ @@ -164,7 +163,7 @@ SCRIPTS_GUI = test16.out # Tests using runtest.vim.vim. -# Keep test_alot.res as the last one, sort the others. +# Keep test_alot*.res as the last one, sort the others. NEW_TESTS = test_arglist.res \ test_assert.res \ test_backspace_opt.res \ @@ -175,6 +174,7 @@ NEW_TESTS = test_arglist.res \ test_increment.res \ test_json.res \ test_langmap.res \ + test_matchadd_conceal.res \ test_packadd.res \ test_perl.res \ test_quickfix.res \ diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index 4d75af3ee9..2b38981bb1 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -60,6 +60,9 @@ let $HOME = '/does/not/exist' let s:srcdir = expand('%:p:h:h') +" Prepare for calling garbagecollect_for_testing(). +let v:testing = 1 + " Support function: get the alloc ID by name. function GetAllocId(name) exe 'split ' . s:srcdir . '/alloc.h' diff --git a/src/testdir/test86.in b/src/testdir/test86.in index cc76cff8d4..6f47ff6813 100644 --- a/src/testdir/test86.in +++ b/src/testdir/test86.in @@ -13,6 +13,7 @@ STARTTEST :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")') @@ -207,7 +208,15 @@ EOF :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :lockvar! l -:py l[2]='i' +py << 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 :" @@ -219,7 +228,7 @@ def ee(expr, g=globals(), l=locals()): exec(expr, g, l) except: ei = sys.exc_info() - msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args) + msg = emsg(ei) msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'') if expr.find('None') > -1: msg = msg.replace('TypeError:(\'iteration over non-sequence\',)', @@ -611,7 +620,6 @@ EOF : autocmd BufFilePre * python cb.append(vim.eval('expand("")') + ':BufFilePre:' + vim.eval('bufnr("%")')) :augroup END py << EOF -cb = vim.current.buffer # Tests BufferAppend and BufferItem cb.append(b[0]) # Tests BufferSlice and BufferAssSlice @@ -865,6 +873,175 @@ EOF :$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={})')) +:" +:" 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 << 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'}) +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)) + +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')) +: +: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 << 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)) + +del s + +del a +del pa1 +del pa2 +del pa3 +del pa4 +del sa +del psa1 +del psa2 +del psa3 +del psa4 +del psar + +del ecall +EOF :" :" Test stdout/stderr :redir => messages @@ -1140,7 +1317,7 @@ 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('\\', '\\\\') +vim.options['rtp'] = os.getcwd().replace('\\', '\\\\').replace(',', '\\,') ee('import xxx_no_such_module_xxx') ee('import failing_import') ee('import failing') @@ -1224,9 +1401,20 @@ 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)') @@ -1381,7 +1569,7 @@ def test_keyboard_interrupt(): except KeyboardInterrupt: cb.append('Caught KeyboardInterrupt') except Exception: - cb.append('!!!!!!!! Caught exception: ' + repr(sys.exc_info)) + cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) else: cb.append('!!!!!!!! No exception') try: @@ -1389,7 +1577,7 @@ def test_keyboard_interrupt(): except KeyboardInterrupt: cb.append('!!!!!!!! Caught KeyboardInterrupt') except Exception: - cb.append('!!!!!!!! Caught exception: ' + repr(sys.exc_info)) + cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) else: cb.append('No exception') EOF @@ -1409,6 +1597,7 @@ EOF py << EOF del cb del ee +del emsg del sys del os del vim @@ -1441,7 +1630,7 @@ EOF :" :/^start:/,$wq! test.out :" vim: et ts=4 isk-=\: -:call getchar() +:while getchar(0) isnot 0|endwhile ENDTEST start: diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok index d103909ca1..fe27c05a7b 100644 --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -57,6 +57,7 @@ None [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'}] @@ -447,7 +448,7 @@ 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__,softspace +function:__dir__,__members__,args,self,softspace output:__dir__,__members__,close,flush,isatty,readable,seekable,softspace,writable,write,writelines {} {'a': 1} @@ -455,12 +456,108 @@ output:__dir__,__members__,close,flush,isatty,readable,seekable,softspace,writab [] ['a', 'b', 'c', '7'] 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: +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'}) +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' ' abcdef -line : +Error detected while processing function RunTest[]..Test: +line : abcdef abcA -line : +line : abcB' ['a', 'dup_a'] ['a', 'a'] @@ -1046,9 +1143,20 @@ 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 vim dictionary',) +vim.Function("tr", args=427423):TypeError:('unable to convert int to vim list',) +vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',) +vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',) +vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to 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',) diff --git a/src/testdir/test87.in b/src/testdir/test87.in index 535a143782..e3bc994ba1 100644 --- a/src/testdir/test87.in +++ b/src/testdir/test87.in @@ -7,6 +7,7 @@ STARTTEST :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")') @@ -200,7 +201,15 @@ EOF :let l = [0, 1, 2, 3] :py3 l=vim.bindeval('l') :lockvar! l -:py3 l[2]='i' +py3 << 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 :" @@ -614,7 +623,6 @@ EOF : autocmd BufFilePre * python3 cb.append(vim.eval('expand("")') + ':BufFilePre:' + vim.eval('bufnr("%")')) :augroup END py3 << EOF -cb = vim.current.buffer # Tests BufferAppend and BufferItem cb.append(b[0]) # Tests BufferSlice and BufferAssSlice @@ -859,6 +867,175 @@ EOF :$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={})')) +:" +:" 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 << 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'}) +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)) + +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')) +: +: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 << 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)) + +del s + +del a +del pa1 +del pa2 +del pa3 +del pa4 +del sa +del psa1 +del psa2 +del psa3 +del psa4 +del psar + +del ecall +EOF :" :" Test stdout/stderr :redir => messages @@ -1134,7 +1311,7 @@ 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('\\', '\\\\') +vim.options['rtp'] = os.getcwd().replace('\\', '\\\\').replace(',', '\\,') ee('import xxx_no_such_module_xxx') ee('import failing_import') ee('import failing') @@ -1218,9 +1395,20 @@ 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)') @@ -1374,16 +1562,16 @@ def test_keyboard_interrupt(): vim.command('while 1 | endwhile') except KeyboardInterrupt: cb.append('Caught KeyboardInterrupt') - except Exception as e: - cb.append('!!!!!!!! Caught exception: ' + repr(e)) + 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 as e: - cb.append('!!!!!!!! Caught exception: ' + repr(e)) + except Exception: + cb.append('!!!!!!!! Caught exception: ' + emsg(sys.exc_info())) else: cb.append('No exception') EOF @@ -1403,6 +1591,7 @@ EOF py3 << EOF del cb del ee +del emsg del sys del os del vim @@ -1434,8 +1623,9 @@ EOF :call garbagecollect(1) :" :/^start:/,$wq! test.out +:/^start:/,$w! test.out :" vim: et ts=4 isk-=\: -:call getchar() +:while getchar(0) isnot 0|endwhile ENDTEST start: diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok index 1d9b6e2578..25c0b51032 100644 --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -57,6 +57,7 @@ None [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'}] @@ -447,7 +448,7 @@ 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__,softspace +function:__dir__,args,self,softspace output:__dir__,close,flush,isatty,readable,seekable,softspace,writable,write,writelines {} {'a': 1} @@ -455,12 +456,108 @@ output:__dir__,close,flush,isatty,readable,seekable,softspace,writable,write,wri [] ['a', 'b', 'c', '7'] 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: +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'}) +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' ' abcdef -line : +Error detected while processing function RunTest[]..Test: +line : abcdef abcA -line : +line : abcB' ['a', 'dup_a'] ['a', 'a'] @@ -1046,9 +1143,20 @@ l.locked = FailingTrue():(, NotImplementedError('bo 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 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',)) diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim index 7f9a1a78fe..d393fe78a4 100644 --- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -17,6 +17,7 @@ source test_join.vim source test_lispwords.vim source test_matchstrpos.vim source test_menu.vim +source test_messages.vim source test_partial.vim source test_reltime.vim source test_searchpos.vim diff --git a/src/testdir/test_alot_utf8.vim b/src/testdir/test_alot_utf8.vim index 20d919c323..8824ee5e15 100644 --- a/src/testdir/test_alot_utf8.vim +++ b/src/testdir/test_alot_utf8.vim @@ -4,4 +4,6 @@ " These tests use utf8 'encoding'. Setting 'encoding' is in the individual " files, so that they can be run by themselves. +source test_expr_utf8.vim +source test_matchadd_conceal_utf8.vim source test_regexp_utf8.vim diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index e1345279fd..05df50af43 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -183,7 +183,7 @@ func s:communicate(port) call assert_equal('got it', s:responseMsg) " Collect garbage, tests that our handle isn't collected. - call garbagecollect() + call garbagecollect_for_testing() " check setting options (without testing the effect) call ch_setoptions(handle, {'callback': 's:NotUsed'}) @@ -1231,7 +1231,7 @@ func Test_job_start_invalid() call assert_fails('call job_start("")', 'E474:') endfunc -" This leaking memory. +" This was leaking memory. func Test_partial_in_channel_cycle() let d = {} let d.a = function('string', [d]) @@ -1243,5 +1243,13 @@ func Test_partial_in_channel_cycle() unlet d endfunc +func Test_using_freed_memory() + let g:a = job_start(['ls']) + sleep 10m + call garbagecollect_for_testing() +endfunc + + + " Uncomment this to see what happens, output is in src/testdir/channellog. " call ch_logfile('channellog', 'w') diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index 33115c7f1f..c8c8e2c2a4 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -50,3 +50,27 @@ func Test_dict() call assert_equal('none', d['']) call assert_equal('aaa', d['a']) endfunc + +func Test_strgetchar() + call assert_equal(char2nr('a'), strgetchar('axb', 0)) + call assert_equal(char2nr('x'), strgetchar('axb', 1)) + call assert_equal(char2nr('b'), strgetchar('axb', 2)) + + call assert_equal(-1, strgetchar('axb', -1)) + call assert_equal(-1, strgetchar('axb', 3)) + call assert_equal(-1, strgetchar('', 0)) +endfunc + +func Test_strcharpart() + call assert_equal('a', strcharpart('axb', 0, 1)) + call assert_equal('x', strcharpart('axb', 1, 1)) + call assert_equal('b', strcharpart('axb', 2, 1)) + call assert_equal('xb', strcharpart('axb', 1)) + + call assert_equal('', strcharpart('axb', 1, 0)) + call assert_equal('', strcharpart('axb', 1, -1)) + call assert_equal('', strcharpart('axb', -1, 1)) + call assert_equal('', strcharpart('axb', -2, 2)) + + call assert_equal('a', strcharpart('axb', -1, 2)) +endfunc diff --git a/src/testdir/test_expr_utf8.vim b/src/testdir/test_expr_utf8.vim new file mode 100644 index 0000000000..c512ddf430 --- /dev/null +++ b/src/testdir/test_expr_utf8.vim @@ -0,0 +1,29 @@ +" Tests for expressions using utf-8. +if !has('multi_byte') + finish +endif +set encoding=utf-8 +scriptencoding utf-8 + +func Test_strgetchar() + call assert_equal(char2nr('á'), strgetchar('áxb', 0)) + call assert_equal(char2nr('x'), strgetchar('áxb', 1)) + + call assert_equal(char2nr('a'), strgetchar('àxb', 0)) + call assert_equal(char2nr('̀'), strgetchar('àxb', 1)) + call assert_equal(char2nr('x'), strgetchar('àxb', 2)) + + call assert_equal(char2nr('あ'), strgetchar('あaい', 0)) + call assert_equal(char2nr('a'), strgetchar('あaい', 1)) + call assert_equal(char2nr('い'), strgetchar('あaい', 2)) +endfunc + +func Test_strcharpart() + call assert_equal('áxb', strcharpart('áxb', 0)) + call assert_equal('á', strcharpart('áxb', 0, 1)) + call assert_equal('x', strcharpart('áxb', 1, 1)) + + call assert_equal('a', strcharpart('àxb', 0, 1)) + call assert_equal('̀', strcharpart('àxb', 1, 1)) + call assert_equal('x', strcharpart('àxb', 2, 1)) +endfunc diff --git a/src/testdir/test_help_tagjump.vim b/src/testdir/test_help_tagjump.vim index d1e9ad422b..f486583bc8 100644 --- a/src/testdir/test_help_tagjump.vim +++ b/src/testdir/test_help_tagjump.vim @@ -15,4 +15,14 @@ func Test_help_tagjump() call assert_equal("help", &filetype) call assert_true(getline('.') =~ "\\*'buflisted'\\*") helpclose + + exec "help! abs({expr})" + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*abs()\*') + helpclose + + exec "help! arglistid([{winnr}" + call assert_equal("help", &filetype) + call assert_true(getline('.') =~ '\*arglistid()\*') + helpclose endfunc diff --git a/src/testdir/test_match_conceal.in b/src/testdir/test_match_conceal.in deleted file mode 100644 index aa32b8582b..0000000000 --- a/src/testdir/test_match_conceal.in +++ /dev/null @@ -1,159 +0,0 @@ -Test for matchadd() and conceal feature - -STARTTEST -:so small.vim -:if !has("conceal") | e! test.ok | w! test.out | qa! | endif -:set term=ansi -:so mbyte.vim -:if &enc !=? 'utf-8'|:e! test.ok|:w! test.out|qa!|endif -:10new|:vsp|:vert resize 20 -:put =\"\#\ This\ is\ a\ Test\" -:norm! mazt -:fu! ScreenChar(width, lines) -: let c='' -: for j in range(1,a:lines) -: for i in range(1,a:width) -: let c.=nr2char(screenchar(j, i)) -: endfor -: let c.="\n" -: endfor -: return c -:endfu -:fu! ScreenAttr(line, pos, eval) -: let g:attr=[] -: for col in a:pos -: call add(g:attr, screenattr(a:line,col)) -: endfor -: " In case all values are zero, probably the terminal -: " isn't set correctly, so catch that case -: let null = (eval(join(g:attr, '+')) == 0) -: let str=substitute(a:eval, '\d\+', 'g:attr[&]', 'g') -: if null || eval(str) -: :let g:attr_test="OK: ". str -: else -: :let g:attr_test="FAILED: ".str -: :let g:attr_test.="\n". join(g:attr, ' ') -: :let g:attr_test.="\n TERM: ". &term -: endif -:endfu -:fu! DoRecordScreen() -: wincmd l -: $put =printf(\"\n%s\", g:test) -: $put =g:line -: $put =g:attr_test -: wincmd p -:endfu -:let g:test ="Test 1: simple addmatch()" -:call matchadd('Conceal', '\%2l ') -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -: -:let g:test ="Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest)" -:norm! 'azt -:call clearmatches() -:syntax on -:set concealcursor=n conceallevel=1 -:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'}) -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -: -:let g:test ="Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest)" -:norm! 'azt -:set conceallevel=3 -:call clearmatches() -:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'}) -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 1==3 && 1==4 && 0!=5") -:call DoRecordScreen() -: -:let g:test ="Test 4: more match() (should be: #Thisisa Test)" -:norm! 'azt -:call matchadd('ErrorMsg', '\%2l Test', 20, -1, {'conceal': 'X'}) -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 0!=3 && 3==4 && 0!=5 && 3!=5") -:call DoRecordScreen() -: -:let g:test ="Test 5/1: default conceal char (should be: # This is a Test)" -:norm! 'azt -:call clearmatches() -:set conceallevel=1 -:call matchadd('Conceal', '\%2l ', 10, -1, {}) -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -:let g:test ="Test 5/2: default conceal char (should be: #+This+is+a+Test)" -:norm! 'azt -:set listchars=conceal:+ -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -:set listchars&vim -: -:let g:test ="Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest)" -:norm! 'azt -:call clearmatches() -:set conceallevel=1 -:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'}) -:syn match MyConceal /\%2l / conceal containedin=ALL cchar=* -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -:let g:test ="Test 6/2: syn and match conceal (should be: #*This*is*a*Test)" -:norm! 'azt -:call clearmatches() -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -: -:let g:test ="Test 7/1: clear matches" -:norm! 'azt -:syn on -:call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'}) -:let a=getmatches() -:call clearmatches() -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 0==2 && 0==3 && 0==4 && 0==5") -:call DoRecordScreen() -:$put =a -:call setmatches(a) -:norm! 'azt -:let g:test ="Test 7/2: reset match using setmatches()" -:norm! 'azt -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -: -:let g:test ="Test 8: using matchaddpos() (should be #Pis a Test" -:norm! 'azt -:call clearmatches() -:call matchaddpos('Conceal', [[2,2,6]], 10, -1, {'conceal': 'P'}) -:let a=getmatches() -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1!=2 && 0==2 && 0==3 && 0!=4 && 0!=5 && 4==5") -:call DoRecordScreen() -:$put =a -: -:let g:test ="Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest)" -:norm! 'azt -:call clearmatches() -:call matchadd('Conceal', '\%2l ', 20, -1, {'conceal': "\u02d1"}) -:redraw! -:let line=ScreenChar(winwidth(0),1) -:call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") -:call DoRecordScreen() -: -:"sleep 10 -:%w! test.out -:qa! -ENDTEST -dummy text diff --git a/src/testdir/test_match_conceal.ok b/src/testdir/test_match_conceal.ok deleted file mode 100644 index 11c379e2f8..0000000000 --- a/src/testdir/test_match_conceal.ok +++ /dev/null @@ -1,52 +0,0 @@ - -# This is a Test - -Test 1: simple addmatch() -# This is a Test -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] - -Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest) -#XThisXisXaXTest -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] - -Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest) -#ThisisaTest -OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]!=g:attr[5] - -Test 4: more match() (should be: #Thisisa Test) -#Thisisa Test -OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[0]!=g:attr[3] && g:attr[3]==g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[3]!=g:attr[5] - -Test 5/1: default conceal char (should be: # This is a Test) -# This is a Test -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] - -Test 5/2: default conceal char (should be: #+This+is+a+Test) -#+This+is+a+Test -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] - -Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest) -#ZThisZisZaZTest -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] - -Test 6/2: syn and match conceal (should be: #*This*is*a*Test) -#*This*is*a*Test -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] - -Test 7/1: clear matches -# This is a Test -OK: g:attr[0]==g:attr[1] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]==g:attr[4] && g:attr[0]==g:attr[5] -{'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': 10, 'conceal': 'Z'} - -Test 7/2: reset match using setmatches() -#ZThisZisZaZTest -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] - -Test 8: using matchaddpos() (should be #Pis a Test -#Pis a Test -OK: g:attr[0]!=g:attr[1] && g:attr[1]!=g:attr[2] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]!=g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[4]==g:attr[5] -{'group': 'Conceal', 'id': 11, 'priority': 10, 'pos1': [2, 2, 6], 'conceal': 'P'} - -Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest) -#ˑThisˑisˑaˑTest -OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] diff --git a/src/testdir/test_matchadd_conceal.vim b/src/testdir/test_matchadd_conceal.vim new file mode 100644 index 0000000000..5da28160c1 --- /dev/null +++ b/src/testdir/test_matchadd_conceal.vim @@ -0,0 +1,266 @@ +" Test for matchadd() and conceal feature +if !has('conceal') + finish +endif + +if !has('gui_running') && has('unix') + set term=ansi +endif + +function! s:screenline(lnum) abort + let line = [] + for c in range(1, winwidth(0)) + call add(line, nr2char(screenchar(a:lnum, c))) + endfor + return s:trim(join(line, '')) +endfunction + +function! s:trim(str) abort + return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$') +endfunction + +function! Test_simple_matchadd() + new + + 1put='# This is a Test' + " 1234567890123456 + let expect = '# This is a Test' + + call cursor(1, 1) + call matchadd('Conceal', '\%2l ') + redraw! + let lnum = 2 + call assert_equal(expect, s:screenline(lnum)) + call assert_notequal(screenattr(lnum, 1), screenattr(lnum, 2)) + 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)) + + quit! +endfunction + +function! Test_simple_matchadd_and_conceal() + new + setlocal concealcursor=n conceallevel=1 + + 1put='# This is a Test' + " 1234567890123456 + let expect = '#XThisXisXaXTest' + + call cursor(1, 1) + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'}) + redraw! + let lnum = 2 + call assert_equal(expect, s: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)) + + quit! +endfunction + +function! Test_matchadd_and_conceallevel_3() + new + + setlocal conceallevel=3 + " set filetype and :syntax on to change screenattr() + setlocal filetype=conf + syntax on + + 1put='# This is a Test' + " 1234567890123456 + let expect = '#ThisisaTest' + + call cursor(1, 1) + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'}) + redraw! + let lnum = 2 + call assert_equal(expect, s: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_notequal(screenattr(lnum, 1), screenattr(lnum, 16)) + + " more matchadd() + " 1234567890123456 + let expect = '#Thisisa Test' + + call matchadd('ErrorMsg', '\%2l Test', 20, -1, {'conceal': 'X'}) + redraw! + call assert_equal(expect, s:screenline(lnum)) + call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 2)) + call assert_equal(screenattr(lnum, 2) , screenattr(lnum, 7)) + call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 10)) + call assert_equal(screenattr(lnum, 10), screenattr(lnum, 12)) + call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 16)) + call assert_notequal(screenattr(lnum, 10), screenattr(lnum, 16)) + + syntax off + quit! +endfunction + +function! Test_default_conceal_char() + new + setlocal concealcursor=n conceallevel=1 + + 1put='# This is a Test' + " 1234567890123456 + let expect = '# This is a Test' + + call cursor(1, 1) + call matchadd('Conceal', '\%2l ', 10, -1, {}) + redraw! + let lnum = 2 + call assert_equal(expect, s: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)) + + " 1234567890123456 + let expect = '#+This+is+a+Test' + let listchars_save = &listchars + set listchars=conceal:+ + redraw! + + call assert_equal(expect, s: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)) + + let &listchars = listchars_save + quit! +endfunction + +function! Test_syn_and_match_conceal() + new + setlocal concealcursor=n conceallevel=1 + + 1put='# This is a Test' + " 1234567890123456 + let expect = '#ZThisZisZaZTest' + + 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 assert_equal(expect, s: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)) + + " 1234567890123456 + let expect = '#*This*is*a*Test' + call clearmatches() + redraw! + + call assert_equal(expect, s: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)) + + syntax off + quit! +endfunction + +function! Test_clearmatches() + new + setlocal concealcursor=n conceallevel=1 + + 1put='# This is a Test' + " 1234567890123456 + let expect = '# This is a Test' + + call cursor(1, 1) + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'}) + let a = getmatches() + call clearmatches() + redraw! + + let lnum = 2 + call assert_equal(expect, s: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, 16)) + + " reset match using setmatches() + " 1234567890123456 + let expect = '#ZThisZisZaZTest' + call setmatches(a) + redraw! + + call assert_equal(expect, s: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)) + call assert_equal({'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': a[0].id, 'conceal': 'Z'}, a[0]) + + quit! +endfunction + +function! Test_using_matchaddpos() + new + setlocal concealcursor=n conceallevel=1 + " set filetype and :syntax on to change screenattr() + setlocal filetype=conf + syntax on + + 1put='# This is a Test' + " 1234567890123456 + let expect = '#Pis a Test' + + call cursor(1, 1) + call matchaddpos('Conceal', [[2,2,6]], 10, -1, {'conceal': 'P'}) + let a = getmatches() + redraw! + + let lnum = 2 + call assert_equal(expect, s:screenline(lnum)) + call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 2)) + call assert_notequal(screenattr(lnum, 2) , screenattr(lnum, 7)) + call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 7)) + call assert_equal(screenattr(lnum, 1) , screenattr(lnum, 10)) + call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 12)) + call assert_notequal(screenattr(lnum, 1) , screenattr(lnum, 16)) + call assert_equal(screenattr(lnum, 12), screenattr(lnum, 16)) + call assert_equal({'group': 'Conceal', 'id': a[0].id, 'priority': 10, 'pos1': [2, 2, 6], 'conceal': 'P'}, a[0]) + + syntax off + quit! +endfunction + +function! Test_matchadd_repeat_conceal_with_syntax_off() + new + + " To test targets in the same line string is replaced with conceal char + " correctly, repeat 'TARGET' + 1put ='TARGET_TARGETTARGET' + call cursor(1, 1) + redraw + call assert_equal('TARGET_TARGETTARGET', s:screenline(2)) + + setlocal conceallevel=2 + call matchadd('Conceal', 'TARGET', 10, -1, {'conceal': 't'}) + + redraw + call assert_equal('t_tt', s:screenline(2)) + + quit! +endfunction diff --git a/src/testdir/test_matchadd_conceal_utf8.vim b/src/testdir/test_matchadd_conceal_utf8.vim new file mode 100644 index 0000000000..8293fbe75c --- /dev/null +++ b/src/testdir/test_matchadd_conceal_utf8.vim @@ -0,0 +1,45 @@ +" Test for matchadd() and conceal feature using utf-8. +if !has('conceal') || !has('multi_byte') + finish +endif +set encoding=utf-8 +scriptencoding utf-8 + +if !has('gui_running') && has('unix') + set term=ansi +endif + +function! s:screenline(lnum) abort + let line = [] + for c in range(1, winwidth(0)) + call add(line, nr2char(screenchar(a:lnum, c))) + endfor + return s:trim(join(line, '')) +endfunction + +function! s:trim(str) abort + return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$') +endfunction + +function! Test_match_using_multibyte_conceal_char() + new + setlocal concealcursor=n conceallevel=1 + + 1put='# This is a Test' + " 1234567890123456 + let expect = '#ˑThisˑisˑaˑTest' + + call cursor(1, 1) + call matchadd('Conceal', '\%2l ', 20, -1, {'conceal': "\u02d1"}) + redraw! + + let lnum = 2 + call assert_equal(expect, s: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)) + + quit! +endfunction diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim new file mode 100644 index 0000000000..188406e440 --- /dev/null +++ b/src/testdir/test_messages.vim @@ -0,0 +1,40 @@ +" Tests for :messages + +function Test_messages() + let oldmore = &more + try + set nomore + " Avoid the "message maintainer" line. + let $LANG = '' + + let arr = map(range(10), '"hello" . v:val') + for s in arr + echomsg s | redraw + endfor + let result = '' + + " get last two messages + redir => result + 2messages | redraw + redir END + let msg_list = split(result, "\n") + call assert_equal(["hello8", "hello9"], msg_list) + + " clear messages without last one + 1messages clear + redir => result + redraw | messages + redir END + let msg_list = split(result, "\n") + call assert_equal(['hello9'], msg_list) + + " clear all messages + messages clear + redir => result + redraw | messages + redir END + call assert_equal('', result) + finally + let &more = oldmore + endtry +endfunction diff --git a/src/testdir/test_perl.vim b/src/testdir/test_perl.vim index 79e24f4ac8..b523805a89 100644 --- a/src/testdir/test_perl.vim +++ b/src/testdir/test_perl.vim @@ -92,3 +92,14 @@ function Test_VIM_package() perl VIM::SetOption('et') call assert_true(&et) endf + +function Test_stdio() + redir =>l:out + perl <