Hi. Here is my enhanced script.
Should now work for all windows users with python enabled vim too.
(Haven't tested it yet)
If you don't have any comments I'll add it to vimscripts an vim.org
Marc
============= runinbg.vim ======================================================
" author : Marc Weber
" purpose: run commands in background and continue with your work
" os:
" linux with bash or python enabled,
" windows with bash or python enabled (not yet tested but should work)
" usage: see RunMakeInBG
" eg call RunMakeInBG('make all')
" or
" eg call RunMakeInBG(['make','all'])
" todo? kill processes on exit?
" handle stderr output with python, too
let s:normal_colorscheme=g:colors_name"
let s:normal_colorscheme="less"
let s:workinbackground_colorscheme="lilac"
let s:use_python_if_availible=1
let s:tempfile=tempname()
if has('gui-running') " FIXME: get vim executable name insteadn (cargs 0)
let s:vim="gs:vim"
else
let s:vim="s:vim"
endif
let s:vim="/usr/bin/gvim"
" add your tasks here
fun! BackgroundJobHasStarted()
exec 'colorscheme '.s:workinbackground_colorscheme
endfun
" add your tasks here
fun! BackgroundJobHasFinisheed(vimPID)
if len(g:processes)==0
exec 'colorscheme '.s:normal_colorscheme
endif
endfun
fun! ProcessFinished(vimPID,status)
echo 'vimPID '.a:vimPID.' has finished, exit status: '.a:status
let vimPID = a:vimPID " used for exec commond only (se RunMakeInBG)
if exists('g:processes["'.a:vimPID.'"]["vimcmd"]')
echomsg g:processes[a:vimPID]["vimcmd"]
exec g:processes[a:vimPID]["vimcmd"]
endif
let entry = g:processes[a:vimPID]
if !exists('g:finished_processes')
let g:finished_processes={}
endif
let g:finished_processes[a:vimPID] = remove(g:processes,a:vimPID)
call BackgroundJobHasFinisheed(entry)
endfun
.
fun! NotifyProcessId(vimProcessId,pid)
echo 'pid is '.a:pid
let g:processes[a:vimProcessId]['pid']=a:pid
endfun
fun! RunMakeInBG(command)
let vimCmdAfter = "exec 'cfile '.g:processes[vimPID]['stdout']"
let vimPID = NewVimProcessId(a:command, vimCmdAfter)
call RunCommandInBackground(vimPID)
endfun
fun! BashExprCallingVim(vimcmd)
return s:vim." --servername \"".v:servername."\" --remote-send
\"<esc>:".a:vimcmd."<cr>\""
endfun
" creates a new vim process id
" it is a dictionary (object) so that you can attach additional info..
" g:processes[vimID]['cmd'] will be executed
" g:processes[vimID]['vimcmd'] will be executed after termination (see
" RunMakeInBG)
" first parameter command to execute (['executable','arg1','arg2',..])
" snd parameter vim continuation command to be executed after the command has
" finished vimPID will be the current vim identifier (see RunMakeInBG as
" example)
fun NewVimProcessId(cmd,...)
if !exists('g:processes')
let g:processes = {}
endif
if !exists('g:nextVimProcessId')
let g:nextVimProcessId = 1
endif
let g:nextVimProcessId += 1
let vimPID = g:nextVimProcessId
let g:processes[vimPID]={}
if type(a:cmd) != 3
" no array, try splitting the argument into executable and args ( FIXME!)
let cmd = split(a:cmd,' ')
else
let cmd = a:cmd
endif
let g:processes[vimPID]['cmd'] = cmd
if a:0>0
let g:processes[vimPID]['vimcmd']=a:1
endif
return vimPID
endfun
fun CommandToSh(cmd)
let result = []
for i in a:cmd
let i = substitute(i,' ','\ ','g')
let i = substitute(i,'"','\" ','g')
let result += [i]
endfor
return join(result,' ')
endfun
fun! RunCommandInBackground(vimPID)
if !has('clientserver')
echoe "no client-server version"
return
endif
let errorfile = tempname() " not yet implemented
let outfile = tempname()
let g:processes[a:vimPID]['stdout'] = outfile
if has('python') && s:use_python_if_availible
call RunProcessInPythonThread(a:vimPID)
else
" let vim now which pid it is (bash $$ substitution
let shcmd = BashExprCallingVim('call
NotifyProcessId('.a:vimPID.',"$$")').';'
" execute the command! :
let shcmd .= CommandToSh(g:processes[a:vimPID]['cmd']).' &> '.outfile.'; '
" notify vim that the command! has finished
let shcmd .= BashExprCallingVim("call
ProcessFinished('".a:vimPID."',$?)").';'
let cmdtoexecute='sh -c "'.substitute(shcmd,'"','\\"','g').'" &'
let g:processes[a:vimPID]['shcmd'] = cmdtoexecute
call BackgroundJobHasStarted()
call system(cmdtoexecute)
endif
endfun
fun! RunProcessInPythonThread(vimPID)
echo a:vimPID
"exec 'python sys.argv['.a:vimPID.']'
"py << EOF
"vimPID=sys.argv[0]
" if you know a better solution than using g:vimPID than mail me!
let g:vimPID=a:vimPID
let g:use_this_vim = s:vim
py << EOF
vimPID = vim.eval("g:vimPID")
print type(vimPID)
thread=MyThread( vimPID, vim.eval("g:processes['%s']['cmd']"%(vimPID)))
thread.cmd = vim.eval("g:processes['%(vimPID)s']['cmd']"%locals())
thread.stdout = vim.eval("g:processes[%(vimPID)s]['stdout']"%locals())
thread.vim = vim.eval("g:use_this_vim")
thread.servername = vim.eval("v:servername")
thread.start()
EOF
unlet g:vimPID
unlet g:use_this_vim
endfun
if exists('g:pythonthreadclassinitialized')
finish
endif
let g:pythonthreadclassinitialized=1
py << EOF
from subprocess import Popen, PIPE
import threading
import os
import vim
class MyThread ( threading.Thread ):
def __init__(self, vimPID, command):
threading.Thread.__init__(self)
self.vimPID=vimPID
self.command=command
def run ( self ):
popenobj = Popen(self.cmd,stdout=PIPE)
self.executeVimCommand("call
NotifyProcessId(%s,%s)"%(self.vimPID,popenobj.pid))
stdoutwriter = open(self.stdout,'w')
stdoutwriter.writelines(popenobj.stdout.readlines())
stdoutwriter.close()
popenobj.wait()
self.executeVimCommand("call
ProcessFinished(%s,%d)"%(self.vimPID,popenobj.returncode))
def executeVimCommand(self, cmd):
# can't use vim.command here because vim hasn't been written for multiple
# threads. I'm getting Xlib: unexpected async reply (sequence 0x859) ;-)
# will use server commands again
popenobj =
Popen([self.vim,"--servername","%s"%(self.servername),"--remote-send","<esc>:%(cmd)s<cr>"%locals()])
popenobj.wait()
EOF
============= end- =============================================================