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