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" If there is an argument use it instead of "NONE". 170" Returns an empty string on error. 171func GetVimCommand(...) 172 if !filereadable('vimcmd') 173 return '' 174 endif 175 if a:0 == 0 176 let name = 'NONE' 177 else 178 let name = a:1 179 endif 180 let cmd = readfile('vimcmd')[0] 181 let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '') 182 if cmd !~ '-u '. name 183 let cmd = cmd . ' -u ' . name 184 endif 185 let cmd .= ' --not-a-term' 186 let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '') 187 return cmd 188endfunc 189 190" Run Vim, using the "vimcmd" file and "-u NORC". 191" "before" is a list of Vim commands to be executed before loading plugins. 192" "after" is a list of Vim commands to be executed after loading plugins. 193" Plugins are not loaded, unless 'loadplugins' is set in "before". 194" Return 1 if Vim could be executed. 195func RunVim(before, after, arguments) 196 return RunVimPiped(a:before, a:after, a:arguments, '') 197endfunc 198 199func RunVimPiped(before, after, arguments, pipecmd) 200 let cmd = GetVimCommand() 201 if cmd == '' 202 return 0 203 endif 204 let args = '' 205 if len(a:before) > 0 206 call writefile(a:before, 'Xbefore.vim') 207 let args .= ' --cmd "so Xbefore.vim"' 208 endif 209 if len(a:after) > 0 210 call writefile(a:after, 'Xafter.vim') 211 let args .= ' -S Xafter.vim' 212 endif 213 214 exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments 215 216 if len(a:before) > 0 217 call delete('Xbefore.vim') 218 endif 219 if len(a:after) > 0 220 call delete('Xafter.vim') 221 endif 222 return 1 223endfunc 224 225func CanRunGui() 226 return has('gui') && ($DISPLAY != "" || has('gui_running')) 227endfunc 228