1" Functions shared by several tests. 2 3" Only load this script once. 4if exists('*WaitFor') 5 finish 6endif 7 8" Get the name of the Python executable. 9" Also keeps it in s:python. 10func PythonProg() 11 " This test requires the Python command to run the test server. 12 " This most likely only works on Unix and Windows. 13 if has('unix') 14 " We also need the job feature or the pkill command to make sure the server 15 " can be stopped. 16 if !(executable('python') && (has('job') || executable('pkill'))) 17 return '' 18 endif 19 let s:python = 'python' 20 elseif has('win32') 21 " Use Python Launcher for Windows (py.exe) if available. 22 if executable('py.exe') 23 let s:python = 'py.exe' 24 elseif executable('python.exe') 25 let s:python = 'python.exe' 26 else 27 return '' 28 endif 29 else 30 return '' 31 endif 32 return s:python 33endfunc 34 35" Run "cmd". Returns the job if using a job. 36func RunCommand(cmd) 37 let job = 0 38 if has('job') 39 let job = job_start(a:cmd, {"stoponexit": "hup"}) 40 call job_setoptions(job, {"stoponexit": "kill"}) 41 elseif has('win32') 42 exe 'silent !start cmd /c start "test_channel" ' . a:cmd 43 else 44 exe 'silent !' . a:cmd . '&' 45 endif 46 return job 47endfunc 48 49" Read the port number from the Xportnr file. 50func GetPort() 51 let l = [] 52 for i in range(200) 53 try 54 let l = readfile("Xportnr") 55 catch 56 endtry 57 if len(l) >= 1 58 break 59 endif 60 sleep 10m 61 endfor 62 call delete("Xportnr") 63 64 if len(l) == 0 65 " Can't make the connection, give up. 66 return 0 67 endif 68 return l[0] 69endfunc 70 71" Run a Python server for "cmd" and call "testfunc". 72" Always kills the server before returning. 73func RunServer(cmd, testfunc, args) 74 " The Python program writes the port number in Xportnr. 75 call delete("Xportnr") 76 77 if len(a:args) == 1 78 let arg = ' ' . a:args[0] 79 else 80 let arg = '' 81 endif 82 let pycmd = s:python . " " . a:cmd . arg 83 84 try 85 let g:currentJob = RunCommand(pycmd) 86 87 " Wait for up to 2 seconds for the port number to be there. 88 let port = GetPort() 89 if port == 0 90 call assert_false(1, "Can't start " . a:cmd) 91 return 92 endif 93 94 call call(function(a:testfunc), [port]) 95 catch 96 call assert_false(1, 'Caught exception: "' . v:exception . '" in ' . v:throwpoint) 97 finally 98 call s:kill_server(a:cmd) 99 endtry 100endfunc 101 102func s:kill_server(cmd) 103 if has('job') 104 if exists('g:currentJob') 105 call job_stop(g:currentJob) 106 unlet g:currentJob 107 endif 108 elseif has('win32') 109 let cmd = substitute(a:cmd, ".py", '', '') 110 call system('taskkill /IM ' . s:python . ' /T /F /FI "WINDOWTITLE eq ' . cmd . '"') 111 else 112 call system("pkill -f " . a:cmd) 113 endif 114endfunc 115 116" Wait for up to a second for "expr" to become true. 117" Return time slept in milliseconds. With the +reltime feature this can be 118" more than the actual waiting time. Without +reltime it can also be less. 119func WaitFor(expr, ...) 120 let timeout = get(a:000, 0, 1000) 121 " using reltime() is more accurate, but not always available 122 if has('reltime') 123 let start = reltime() 124 else 125 let slept = 0 126 endif 127 for i in range(timeout / 10) 128 try 129 if eval(a:expr) 130 if has('reltime') 131 return float2nr(reltimefloat(reltime(start)) * 1000) 132 endif 133 return slept 134 endif 135 catch 136 endtry 137 if !has('reltime') 138 let slept += 10 139 endif 140 sleep 10m 141 endfor 142 return timeout 143endfunc 144 145" Wait for up to a given milliseconds. 146" With the +timers feature this waits for key-input by getchar(), Resume() 147" feeds key-input and resumes process. Return time waited in milliseconds. 148" Without +timers it uses simply :sleep. 149func Standby(msec) 150 if has('timers') 151 let start = reltime() 152 let g:_standby_timer = timer_start(a:msec, function('s:feedkeys')) 153 call getchar() 154 return float2nr(reltimefloat(reltime(start)) * 1000) 155 else 156 execute 'sleep ' a:msec . 'm' 157 return a:msec 158 endif 159endfunc 160 161func Resume() 162 if exists('g:_standby_timer') 163 call timer_stop(g:_standby_timer) 164 call s:feedkeys(0) 165 unlet g:_standby_timer 166 endif 167endfunc 168 169func s:feedkeys(timer) 170 call feedkeys('x', 'nt') 171endfunc 172 173" Get the command to run Vim, with -u NONE and --not-a-term arguments. 174" If there is an argument use it instead of "NONE". 175" Returns an empty string on error. 176func GetVimCommand(...) 177 if !filereadable('vimcmd') 178 return '' 179 endif 180 if a:0 == 0 181 let name = 'NONE' 182 else 183 let name = a:1 184 endif 185 let cmd = readfile('vimcmd')[0] 186 let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '') 187 if cmd !~ '-u '. name 188 let cmd = cmd . ' -u ' . name 189 endif 190 let cmd .= ' --not-a-term' 191 let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '') 192 return cmd 193endfunc 194 195" Run Vim, using the "vimcmd" file and "-u NORC". 196" "before" is a list of Vim commands to be executed before loading plugins. 197" "after" is a list of Vim commands to be executed after loading plugins. 198" Plugins are not loaded, unless 'loadplugins' is set in "before". 199" Return 1 if Vim could be executed. 200func RunVim(before, after, arguments) 201 return RunVimPiped(a:before, a:after, a:arguments, '') 202endfunc 203 204func RunVimPiped(before, after, arguments, pipecmd) 205 let cmd = GetVimCommand() 206 if cmd == '' 207 return 0 208 endif 209 let args = '' 210 if len(a:before) > 0 211 call writefile(a:before, 'Xbefore.vim') 212 let args .= ' --cmd "so Xbefore.vim"' 213 endif 214 if len(a:after) > 0 215 call writefile(a:after, 'Xafter.vim') 216 let args .= ' -S Xafter.vim' 217 endif 218 219 exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments 220 221 if len(a:before) > 0 222 call delete('Xbefore.vim') 223 endif 224 if len(a:after) > 0 225 call delete('Xafter.vim') 226 endif 227 return 1 228endfunc 229 230func CanRunGui() 231 return has('gui') && ($DISPLAY != "" || has('gui_running')) 232endfunc 233