" asyncrun.vim - Run shell commands in background and output to quickfix " " Maintainer: skywind3000 (at) gmail.com " Homepage: http://www.vim.org/scripts/script.php?script_id=5431 " " Last change: 2016.11.8 " " Run shell command in background and output to quickfix: " :AsyncRun[!] [options] {cmd} ... " " when "!" is included, auto-scroll in quickfix will be disabled " parameters are splited by space, if a parameter contains space, " it should be quoted or escaped as backslash + space (unix only). " " Parameters will be expanded if they start with '%', '#' or '<' : " %:p - File name of current buffer with full path " %:t - File name of current buffer without path " %:p:h - File path of current buffer without file name " %:e - File extension of current buffer " %:t:r - File name of current buffer without path and extension " % - File name relativize to current directory " %:h:. - File path relativize to current directory " - Current directory " - Current word under cursor " - Current file name under cursor " " Environment variables are set before executing: " $VIM_FILEPATH - File name of current buffer with full path " $VIM_FILENAME - File name of current buffer without path " $VIM_FILEDIR - Full path of current buffer without the file name " $VIM_FILEEXT - File extension of current buffer " $VIM_FILENOEXT - File name of current buffer without path and extension " $VIM_CWD - Current directory " $VIM_RELDIR - File path relativize to current directory " $VIM_RELNAME - File name relativize to current directory " $VIM_CWORD - Current word under cursor " $VIM_CFILE - Current filename under cursor " $VIM_GUI - Is running under gui ? " $VIM_VERSION - Value of v:version " $VIM_MODE - Execute via 0:!, 1:makeprg, 2:system(), 3:silent " $VIM_COLUMNS - How many columns in vim's screen " $VIM_LINES - How many lines in vim's screen " " parameters also accept these environment variables wrapped by " "$(...)", and "$(VIM_FILEDIR)" will be expanded as file directory " " There can be some options before [cmd]: " -mode=0/1/2 - start mode: 0(async, default), 1(makeprg), 2(!) " -cwd=? - initial directory, (use current directory if unset) " -save=0/1 - non-zero to save unsaved files before executing " -program=? - set to 'make' to use '&makeprg' " " All options must start with a minus and position **before** `[cmd]`. " Since no shell command starts with a minus. So they can be " distinguished from shell command easily without any ambiguity. " " Stop the running job by signal TERM: " :AsyncStop[!] " " when "!" is included, job will be stopped by signal KILL " " Settings: " g:asyncrun_exit - script will be executed after finished " g:asyncrun_bell - non-zero to ring a bell after finished " g:asyncrun_mode - 0:async(require vim 7.4.1829) 1:sync 2:shell " g:asyncrun_encs - shell program output encoding " " Variables: " g:asyncrun_code - exit code " g:asyncrun_status - 'running', 'success' or 'failure' " " Requirements: " vim 7.4.1829 is minimal version to support async mode " " Examples: " :AsyncRun gcc % -o %< " :AsyncRun make -f Mymakefile " :AsyncRun! grep -R . " :noremap :AsyncRun gcc % -o %< " " Additional: " AsyncRun uses quickfix window to show job outputs, in order to " see the outputs in realtime, you need open quickfix window at " first by using :copen (see :help copen/cclose). Or use " ':call asyncrun#quickfix_toggle(8)' to open/close it rapidly. " "---------------------------------------------------------------------- "- Global Settings & Variables "---------------------------------------------------------------------- if !exists('g:asyncrun_exit') let g:asyncrun_exit = '' endif if !exists('g:asyncrun_bell') let g:asyncrun_bell = 0 endif if !exists('g:asyncrun_stop') let g:asyncrun_stop = '' endif if !exists('g:asyncrun_mode') let g:asyncrun_mode = 0 endif if !exists('g:asyncrun_hook') let g:asyncrun_hook = '' endif if !exists('g:asyncrun_last') let g:asyncrun_last = 0 endif if !exists('g:asyncrun_timer') let g:asyncrun_timer = 100 endif if !exists('g:asyncrun_code') let g:asyncrun_code = '' endif if !exists('g:asyncrun_status') let g:asyncrun_status = '' endif if !exists('g:asyncrun_encs') let g:asyncrun_encs = '' endif if !exists('g:asyncrun_trim') let g:asyncrun_trim = 0 endif if !exists('g:asyncrun_text') let g:asyncrun_text = '' endif if !exists('g:asyncrun_local') let g:asyncrun_local = 1 endif if !exists('g:asyncrun_auto') let g:asyncrun_auto = '' endif "---------------------------------------------------------------------- "- Internal Functions "---------------------------------------------------------------------- " error message function! s:ErrorMsg(msg) echohl ErrorMsg echom 'ERROR: '. a:msg echohl NONE endfunc " show not support message function! s:NotSupport() let msg = "required: +timers +channel +job +reltime and vim >= 7.4.1829" call s:ErrorMsg(msg) endfunc let s:asyncrun_windows = 0 let g:asyncrun_windows = 0 let s:asyncrun_support = 0 let g:asyncrun_support = 0 " check running in windows if has('win32') || has('win64') || has('win95') || has('win16') let s:asyncrun_windows = 1 let g:asyncrun_windows = 1 endif " check has advanced mode if (v:version >= 800 || has('patch-7.4.1829')) && (!has('nvim')) if has('job') && has('channel') && has('timers') && has('reltime') let s:asyncrun_support = 1 let g:asyncrun_support = 1 endif elseif has('nvim') let s:asyncrun_support = 1 let g:asyncrun_support = 1 endif "---------------------------------------------------------------------- "- build in background "---------------------------------------------------------------------- let s:async_nvim = has('nvim')? 1 : 0 let s:async_info = { 'text':"", 'post':'', 'postsave':'' } let s:async_output = {} let s:async_head = 0 let s:async_tail = 0 let s:async_code = 0 let s:async_state = 0 let s:async_start = 0.0 let s:async_debug = 0 let s:async_quick = 0 let s:async_scroll = 0 let s:async_hold = 0 let s:async_efm = &errorformat " check :cbottom available, cursor in quick need to hold ? if s:async_nvim == 0 let s:async_quick = (v:version >= 800 || has('patch-7.4.1997'))? 1 : 0 let s:async_hold = (v:version >= 800 || has('patch-7.4.2100'))? 0 : 1 else let s:async_quick = 0 let s:async_hold = 1 endif " scroll quickfix down function! s:AsyncRun_Job_Scroll() if &buftype == 'quickfix' silent exec 'normal! G' endif endfunc " quickfix window cursor check function! s:AsyncRun_Job_Cursor() if &buftype == 'quickfix' if s:async_hold != 0 let w:asyncrun_qfview = winsaveview() endif if line('.') != line('$') let s:async_check_last = 0 endif endif endfunc " find quickfix window and scroll to the bottom then return last window function! s:AsyncRun_Job_AutoScroll() if s:async_quick == 0 let l:winnr = winnr() windo call s:AsyncRun_Job_Scroll() silent exec ''.l:winnr.'wincmd w' else cbottom endif endfunc " restore view in old vim/neovim function! s:AsyncRun_Job_ViewReset() if &buftype == 'quickfix' if exists('w:asyncrun_qfview') call winrestview(w:asyncrun_qfview) unlet w:asyncrun_qfview endif endif endfunc " it will reset cursor when caddexpr is invoked function! s:AsyncRun_Job_QuickReset() if &buftype == 'quickfix' call s:AsyncRun_Job_ViewReset() else let l:winnr = winnr() windo call s:AsyncRun_Job_ViewReset() silent exec ''.l:winnr.'wincmd w' endif endfunc " check if quickfix window can scroll now function! s:AsyncRun_Job_CheckScroll() if g:asyncrun_last == 0 if &buftype == 'quickfix' if s:async_hold != 0 let w:asyncrun_qfview = winsaveview() endif return (line('.') == line('$')) else return 1 endif elseif g:asyncrun_last == 1 let s:async_check_last = 1 let l:winnr = winnr() windo call s:AsyncRun_Job_Cursor() silent exec ''.l:winnr.'wincmd w' return s:async_check_last elseif g:asyncrun_last == 2 return 1 else if &buftype == 'quickfix' if s:async_hold != 0 let w:asyncrun_qfview = winsaveview() endif return (line('.') == line('$')) else return (!pumvisible()) endif endif endfunc " invoked on timer or finished function! s:AsyncRun_Job_Update(count) let l:iconv = (g:asyncrun_encs != "")? 1 : 0 let l:count = 0 let l:total = 0 let l:empty = [{'text':''}] let l:check = s:AsyncRun_Job_CheckScroll() let l:efm1 = &g:efm let l:efm2 = &l:efm if g:asyncrun_encs == &encoding let l:iconv = 0 endif if &g:efm != s:async_efm && g:asyncrun_local != 0 let &l:efm = s:async_efm let &g:efm = s:async_efm endif let l:raw = (s:async_efm == '')? 1 : 0 while s:async_tail < s:async_head let l:text = s:async_output[s:async_tail] if l:iconv != 0 try let l:text = iconv(l:text, g:asyncrun_encs, &encoding) catch /.*/ endtry endif if l:text != '' if l:raw == 0 caddexpr l:text else call setqflist([{'text':l:text}], 'a') endif elseif g:asyncrun_trim == 0 call setqflist(l:empty, 'a') endif let l:total += 1 unlet s:async_output[s:async_tail] let s:async_tail += 1 let l:count += 1 if a:count > 0 && l:count >= a:count break endif endwhile if g:asyncrun_local != 0 if l:efm1 != &g:efm | let &g:efm = l:efm1 | endif if l:efm2 != &l:efm | let &l:efm = l:efm2 | endif endif if s:async_scroll != 0 && l:total > 0 && l:check != 0 call s:AsyncRun_Job_AutoScroll() elseif s:async_hold != 0 call s:AsyncRun_Job_QuickReset() endif return l:count endfunc " trigger autocmd function! s:AsyncRun_Job_AutoCmd(mode, auto) if !has('autocmd') | return | endif let name = (a:auto == '')? g:asyncrun_auto : a:auto if name !~ '^\w\+' || name == 'NONE' || name == '' return endif if a:mode == 0 exec 'silent doautocmd QuickFixCmdPre '. name else exec 'silent doautocmd QuickFixCmdPost '. name endif endfunc " invoked on timer function! g:AsyncRun_Job_OnTimer(id) if exists('s:async_job') call job_status(s:async_job) endif call s:AsyncRun_Job_Update(5 + g:asyncrun_timer) endfunc " invoked on "callback" when job output function! s:AsyncRun_Job_OnCallback(channel, text) if !exists("s:async_job") return endif if type(a:text) != 1 return endif let s:async_output[s:async_head] = a:text let s:async_head += 1 if g:asyncrun_timer <= 0 call s:AsyncRun_Job_Update(-1) endif endfunc " because exit_cb and close_cb are disorder, we need OnFinish to guarantee " both of then have already invoked function! s:AsyncRun_Job_OnFinish(what) " caddexpr '(OnFinish): '.a:what.' '.s:async_state if s:async_state == 0 return -1 endif if a:what == 0 let s:async_state = or(s:async_state, 2) elseif a:what == 1 let s:async_state = or(s:async_state, 4) else let s:async_state = 7 endif if and(s:async_state, 7) != 7 return -2 endif if exists('s:async_job') unlet s:async_job endif if exists('s:async_timer') call timer_stop(s:async_timer) unlet s:async_timer endif call s:AsyncRun_Job_Update(-1) let l:current = float2nr(reltimefloat(reltime())) let l:last = l:current - s:async_start let l:check = s:AsyncRun_Job_CheckScroll() if s:async_code == 0 let l:text = "[Finished in ".l:last." seconds]" call setqflist([{'text':l:text}], 'a') let g:asyncrun_status = "success" else let l:text = 'with code '.s:async_code let l:text = "[Finished in ".l:last." seconds ".l:text."]" call setqflist([{'text':l:text}], 'a') let g:asyncrun_status = "failure" endif let s:async_state = 0 if s:async_scroll != 0 && l:check != 0 call s:AsyncRun_Job_AutoScroll() elseif s:async_hold != 0 call s:AsyncRun_Job_QuickReset() endif let g:asyncrun_code = s:async_code if g:asyncrun_bell != 0 exec "norm! \" endif redrawstatus! redraw if s:async_info.post != '' exec s:async_info.post let s:async_info.post = '' endif if g:asyncrun_exit != "" exec g:asyncrun_exit endif call s:AsyncRun_Job_AutoCmd(1, s:async_info.auto) endfunc " invoked on "close_cb" when channel closed function! s:AsyncRun_Job_OnClose(channel) " caddexpr "[close]" let s:async_debug = 1 let l:limit = 128 while ch_status(a:channel) == 'buffered' let l:text = ch_read(a:channel) if l:text == '' " important when child process is killed let l:limit -= 1 if l:limit < 0 | break | endif else call s:AsyncRun_Job_OnCallback(a:channel, l:text) endif endwhile let s:async_debug = 0 call s:AsyncRun_Job_Update(-1) call s:AsyncRun_Job_OnFinish(1) if exists('s:async_job') call job_status(s:async_job) endif endfunc " invoked on "exit_cb" when job exited function! s:AsyncRun_Job_OnExit(job, message) " caddexpr "[exit]: ".a:message." ".type(a:message) let s:async_code = a:message call s:AsyncRun_Job_OnFinish(0) endfunc " invoked on neovim when stderr/stdout/exit function! s:AsyncRun_Job_NeoVim(job_id, data, event) if a:event == 'stdout' || a:event == 'stderr' let l:index = 0 let l:size = len(a:data) while l:index < l:size let s:async_output[s:async_head] = a:data[l:index] let s:async_head += 1 let l:index += 1 endwhile call s:AsyncRun_Job_Update(-1) elseif a:event == 'exit' if type(a:data) == type(1) let s:async_code = a:data endif call s:AsyncRun_Job_OnFinish(2) endif endfunc "---------------------------------------------------------------------- " AsyncRun Interface "---------------------------------------------------------------------- " start background build function! s:AsyncRun_Job_Start(cmd) let l:running = 0 let l:empty = 0 if s:asyncrun_support == 0 call s:NotSupport() return -1 endif if exists('s:async_job') if !has('nvim') if job_status(s:async_job) == 'run' let l:running = 1 endif else if s:async_job > 0 let l:running = 1 endif endif endif if type(a:cmd) == 1 if a:cmd == '' | let l:empty = 1 | endif elseif type(a:cmd) == 3 if a:cmd == [] | let l:empty = 1 | endif endif if s:async_state != 0 || l:running != 0 call s:ErrorMsg("background job is still running") return -2 endif if l:empty != 0 call s:ErrorMsg("empty arguments") return -3 endif if !executable(&shell) let l:text = "invalid config in &shell and &shellcmdflag" call s:ErrorMsg(l:text . ", &shell must be an executable.") return -4 endif let l:args = [&shell, &shellcmdflag] let l:name = [] if type(a:cmd) == 1 let l:name = a:cmd if s:asyncrun_windows == 0 let l:args += [a:cmd] else let l:tmp = fnamemodify(tempname(), ':h') . '\asyncrun.cmd' let l:run = ['@echo off', a:cmd] call writefile(l:run, l:tmp) let l:args += [l:tmp] endif elseif type(a:cmd) == 3 if s:asyncrun_windows == 0 let l:temp = [] for l:item in a:cmd if index(['|', '`'], l:item) < 0 let l:temp += [fnameescape(l:item)] else let l:temp += ['|'] endif endfor let l:args += [join(l:temp, ' ')] else let l:args += a:cmd endif let l:vector = [] for l:x in a:cmd let l:vector += ['"'.l:x.'"'] endfor let l:name = join(l:vector, ', ') endif let s:async_efm = &errorformat if s:async_nvim == 0 let l:options = {} let l:options['callback'] = function('s:AsyncRun_Job_OnCallback') let l:options['close_cb'] = function('s:AsyncRun_Job_OnClose') let l:options['exit_cb'] = function('s:AsyncRun_Job_OnExit') let l:options['out_io'] = 'pipe' let l:options['err_io'] = 'out' let l:options['in_io'] = 'null' let l:options['out_mode'] = 'nl' let l:options['err_mode'] = 'nl' let l:options['stoponexit'] = 'term' if g:asyncrun_stop != '' let l:options['stoponexit'] = g:asyncrun_stop endif let s:async_job = job_start(l:args, l:options) let l:success = (job_status(s:async_job) != 'fail')? 1 : 0 else let l:callbacks = {'shell': 'AsyncRun'} let l:callbacks['on_stdout'] = function('s:AsyncRun_Job_NeoVim') let l:callbacks['on_stderr'] = function('s:AsyncRun_Job_NeoVim') let l:callbacks['on_exit'] = function('s:AsyncRun_Job_NeoVim') let s:async_job = jobstart(l:args, l:callbacks) let l:success = (s:async_job > 0)? 1 : 0 endif if l:success != 0 let s:async_output = {} let s:async_head = 0 let s:async_tail = 0 let l:arguments = "[".l:name."]" let l:title = ':AsyncRun '.l:name if s:async_nvim == 0 if v:version >= 800 || has('patch-7.4.2210') call setqflist([], ' ', {'title':l:title}) else call setqflist([], '') endif else call setqflist([], ' ', l:title) endif call setqflist([{'text':l:arguments}], 'a') let s:async_start = float2nr(reltimefloat(reltime())) if g:asyncrun_timer > 0 && s:async_nvim == 0 let l:options = {'repeat':-1} let l:name = 'g:AsyncRun_Job_OnTimer' let s:async_timer = timer_start(100, l:name, l:options) endif let s:async_state = 1 let g:asyncrun_status = "running" let s:async_info.post = s:async_info.postsave let s:async_info.auto = s:async_info.autosave let s:async_info.postsave = '' let s:async_info.autosave = '' let g:asyncrun_text = s:async_info.text redrawstatus! call s:AsyncRun_Job_AutoCmd(0, s:async_info.auto) else unlet s:async_job call s:ErrorMsg("Background job start failed '".a:cmd."'") return -5 endif return 0 endfunc " stop background job function! s:AsyncRun_Job_Stop(how) let l:how = (a:how != '')? a:how : 'term' if s:asyncrun_support == 0 call s:NotSupport() return -1 endif if exists('s:async_job') if s:async_nvim == 0 if job_status(s:async_job) == 'run' if job_stop(s:async_job, l:how) return 0 else return -2 endif else return -3 endif else if s:async_job > 0 call jobstop(s:async_job) endif endif else return -4 endif return 0 endfunc " get job status function! s:AsyncRun_Job_Status() if exists('s:async_job') if s:async_nvim == 0 return job_status(s:async_job) else return 'run' endif else return 'none' endif endfunc "---------------------------------------------------------------------- " Utilities "---------------------------------------------------------------------- " Replace string function! s:StringReplace(text, old, new) let l:data = split(a:text, a:old, 1) return join(l:data, a:new) endfunc " Trim leading and tailing spaces function! s:StringStrip(text) return substitute(a:text, '^\s*\(.\{-}\)\s*$', '\1', '') endfunc " extract options from command function! s:ExtractOpt(command) let cmd = a:command let opts = {} while cmd =~# '^-\%(\w\+\)\%([= ]\|$\)' let opt = matchstr(cmd, '^-\zs\w\+') if cmd =~ '^-\w\+=' let val = matchstr(cmd, '^-\w\+=\zs\%(\\.\|\S\)*') else let val = (opt == 'cwd')? '' : 1 endif let opts[opt] = substitute(val, '\\\(\s\)', '\1', 'g') let cmd = substitute(cmd, '^-\w\+\%(=\%(\\.\|\S\)*\)\=\s*', '', '') endwhile let cmd = substitute(cmd, '^\s*\(.\{-}\)\s*$', '\1', '') let cmd = substitute(cmd, '^@\s*', '', '') let opts.cwd = get(opts, 'cwd', '') let opts.mode = get(opts, 'mode', '') let opts.save = get(opts, 'save', '') let opts.program = get(opts, 'program', '') let opts.post = get(opts, 'post', '') let opts.text = get(opts, 'text', '') let opts.auto = get(opts, 'auto', '') if 0 echom 'cwd:'. opts.cwd echom 'mode:'. opts.mode echom 'save:'. opts.save echom 'program:'. opts.program echom 'command:'. cmd endif return [cmd, opts] endfunc " write script to a file and return filename function! s:ScriptWrite(command, pause) let l:tmp = fnamemodify(tempname(), ':h') . '\asyncrun.cmd' if s:asyncrun_windows != 0 let l:line = ['@echo off', 'call '.a:command] if a:pause != 0 let l:line += ['pause'] endif else let l:line = ['#! '.&shell] let l:line += [a:command] if a:pause != 0 let l:line += ['read -n1 -rsp "press any key to confinue ..."'] endif let l:tmp = tempname() endif if v:version >= 700 call writefile(l:line, l:tmp) else exe 'redir ! > '.fnameescape(l:tmp) for l:index in range(len(l:line)) silent echo l:line[l:index] endfor redir END endif return l:tmp endfunc "---------------------------------------------------------------------- " asyncrun - run "---------------------------------------------------------------------- function! asyncrun#run(bang, opts, args) let l:macros = {} let l:macros['VIM_FILEPATH'] = expand("%:p") let l:macros['VIM_FILENAME'] = expand("%:t") let l:macros['VIM_FILEDIR'] = expand("%:p:h") let l:macros['VIM_FILENOEXT'] = expand("%:t:r") let l:macros['VIM_FILEEXT'] = "." . expand("%:e") let l:macros['VIM_CWD'] = getcwd() let l:macros['VIM_RELDIR'] = expand("%:h:.") let l:macros['VIM_RENAME'] = expand("%:p:.") let l:macros['VIM_CWORD'] = expand("") let l:macros['VIM_CFILE'] = expand("") let l:macros['VIM_VERSION'] = ''.v:version let l:macros['VIM_SVRNAME'] = v:servername let l:macros['VIM_COLUMNS'] = ''.&columns let l:macros['VIM_LINES'] = ''.&lines let l:macros['VIM_GUI'] = has('gui_running')? 1 : 0 let l:macros[''] = getcwd() let l:command = s:StringStrip(a:args) let cd = haslocaldir()? 'lcd ' : 'cd ' let l:retval = '' " extract options let [l:command, l:opts] = s:ExtractOpt(l:command) " replace macros and setup environment variables for [l:key, l:val] in items(l:macros) let l:replace = (l:key[0] != '<')? '$('.l:key.')' : l:key if l:key[0] != '<' exec 'let $'.l:key.' = l:val' endif let l:command = s:StringReplace(l:command, l:replace, l:val) let l:opts.cwd = s:StringReplace(l:opts.cwd, l:replace, l:val) let l:opts.text = s:StringReplace(l:opts.text, l:replace, l:val) endfor " combine options if type(a:opts) == type({}) for [l:key, l:val] in items(a:opts) let l:opts[l:key] = l:val endfor endif " check if need to save if get(l:opts, 'save', '') try | silent update | catch | endtry endif if a:bang == '!' let s:async_scroll = 0 else let s:async_scroll = 1 endif " check mode let l:mode = g:asyncrun_mode if l:opts.mode != '' let l:mode = l:opts.mode endif " process makeprg/grepprg in -program=? let l:program = "" if l:opts.program == 'make' let l:program = &makeprg elseif l:opts.program == 'grep' let l:program = &grepprg endif if l:program != '' if l:program =~# '\$\*' let l:command = s:StringReplace(l:program, '\$\*', l:command) elseif l:command != '' let l:command = l:program . ' ' . l:command else let l:command = l:program endif let l:command = s:StringStrip(l:command) endif if l:command =~ '^\s*$' echohl ErrorMsg echom "E471: Command required" echohl NONE return endif if l:mode >= 10 let l:opts.cmd = l:command let l:opts.mode = l:mode if g:asyncrun_hook != '' exec 'call '. g:asyncrun_hook .'(l:opts)' endif return endif if l:opts.cwd != '' let l:opts.savecwd = getcwd() try silent exec cd . fnameescape(l:opts.cwd) catch /.*/ echohl ErrorMsg echom "E344: Can't find directory \"".l:opts.cwd."\" in -cwd" echohl NONE return endtry endif if l:mode == 0 && s:asyncrun_support != 0 let s:async_info.postsave = opts.post let s:async_info.autosave = opts.auto let s:async_info.text = opts.text call s:AsyncRun_Job_Start(l:command) elseif l:mode <= 1 && has('quickfix') let l:makesave = &l:makeprg let l:script = s:ScriptWrite(l:command, 0) if s:asyncrun_windows != 0 let &l:makeprg = shellescape(l:script) else let &l:makeprg = 'source '. shellescape(l:script) endif if has('autocmd') call s:AsyncRun_Job_AutoCmd(0, opts.auto) exec "noautocmd make!" call s:AsyncRun_Job_AutoCmd(1, opts.auto) else exec "make!" endif let &l:makeprg = l:makesave if s:asyncrun_windows == 0 try | call delete(l:script) | catch | endtry endif let g:asyncrun_text = opts.text if opts.post != '' exec opts.post endif elseif l:mode <= 2 exec '!'. l:command let g:asyncrun_text = opts.text if opts.post != '' exec opts.post endif elseif l:mode == 3 if s:asyncrun_windows != 0 && has('python') let l:script = s:ScriptWrite(l:command, 0) python import vim, subprocess python x = [vim.eval('l:script')] python m = subprocess.PIPE python n = subprocess.STDOUT python s = True python p = subprocess.Popen(x, shell = s, stdout = m, stderr = n) python t = p.stdout.read() python p.stdout.close() python p.wait() python t = t.replace('\\', '\\\\').replace('"', '\\"') python t = t.replace('\n', '\\n').replace('\r', '\\r') python vim.command('let l:text = "%s"'%t) let l:retval = l:text else let l:retval = system(l:command) endif let g:asyncrun_text = opts.text if opts.post != '' exec opts.post endif elseif l:mode <= 5 if s:asyncrun_windows != 0 && has('gui_running') let l:ccc = shellescape(s:ScriptWrite(l:command, 1)) if l:mode == 4 silent exec '!start cmd /C '. l:ccc else silent exec '!start /b cmd /C '. l:ccc endif redraw else if l:mode == 4 exec '!' . l:command else call system(l:command . ' &') endif endif let g:asyncrun_text = opts.text if opts.post != '' exec opts.post endif endif if l:opts.cwd != '' silent exec cd fnameescape(l:opts.savecwd) endif return l:retval endfunc "---------------------------------------------------------------------- " asyncrun - stop "---------------------------------------------------------------------- function! asyncrun#stop(bang) if a:bang == '' return s:AsyncRun_Job_Stop('term') else return s:AsyncRun_Job_Stop('kill') endif endfunc "---------------------------------------------------------------------- " asyncrun - status "---------------------------------------------------------------------- function! asyncrun#status() return s:AsyncRun_Job_Status() endfunc "---------------------------------------------------------------------- " asyncrun -version "---------------------------------------------------------------------- function! asyncrun#version() return '1.3.0' endfunc "---------------------------------------------------------------------- " Commands "---------------------------------------------------------------------- command! -bang -nargs=+ -complete=file AsyncRun \ call asyncrun#run('', '', ) command! -bang -nargs=0 AsyncStop call asyncrun#stop('') "---------------------------------------------------------------------- " Fast command to toggle quickfix "---------------------------------------------------------------------- function! asyncrun#quickfix_toggle(size, ...) let l:mode = (a:0 == 0)? 2 : (a:1) function! s:WindowCheck(mode) if &buftype == 'quickfix' let s:quickfix_open = 1 return endif if a:mode == 0 let w:quickfix_save = winsaveview() else if exists('w:quickfix_save') call winrestview(w:quickfix_save) unlet w:quickfix_save endif endif endfunc let s:quickfix_open = 0 let l:winnr = winnr() noautocmd windo call s:WindowCheck(0) noautocmd silent! exec ''.l:winnr.'wincmd w' if l:mode == 0 if s:quickfix_open != 0 silent! cclose endif elseif l:mode == 1 if s:quickfix_open == 0 exec 'botright copen '. ((a:size > 0)? a:size : ' ') wincmd k endif elseif l:mode == 2 if s:quickfix_open == 0 exec 'botright copen '. ((a:size > 0)? a:size : ' ') wincmd k else silent! cclose endif endif noautocmd windo call s:WindowCheck(1) noautocmd silent! exec ''.l:winnr.'wincmd w' endfunc