I'm writing a PyQt programe where I'd like to allow the user to launch their preferred editor to fill in a TextEdit field.
So the goal is to launch an editor (say vim) externally on a tmp file, and upon editor closing, get its contexts into a python variable.
I've found a few similar questions like Opening vi from Python, call up an EDITOR (vim) from a python script, invoke an editor ( vim ) in python. But they are all in a "blocking" manner that works like the git commit
command. What I am after is a "non-blocking" manner (because it is a GUI), something like the "Edit Source" function in zimwiki.
My current attempt:
import os
import tempfile
import threading
import subprocess
def popenAndCall(onExit, popenArgs):
def runInThread(onExit, popenArgs):
tmppath=popenArgs[-1]
proc = subprocess.Popen(popenArgs)
# this immediately finishes OPENING vim.
rec=proc.wait()
print('# <runInThread>: rec=', rec)
onExit(tmppath)
os.remove(tmppath)
return
thread = threading.Thread(target=runInThread, args=(onExit, popenArgs))
thread.start()
return thread
def openEditor():
fd, filepath=tempfile.mkstemp()
print('filepath=',filepath)
def cb(tmppath):
print('# <cb>: cb tmppath=',tmppath)
with open(tmppath, 'r') as tmp:
lines=tmp.readlines()
for ii in lines:
print('# <cb>: ii',ii)
return
with os.fdopen(fd, 'w') as tmp:
cmdflag='--'
editor_cmd='vim'
cmd=[os.environ['TERMCMD'], cmdflag, editor_cmd, filepath]
print('#cmd = ',cmd)
popenAndCall(cb, cmd)
print('done')
return
if __name__=='__main__':
openEditor()
I think it failed because the Popen.wait()
only waits until the editor is opened, not until its closing. So it captures nothing from the editor.
Any idea how to solve this? Thanks!
EDIT:
I found this answer which I guess is related. I'm messing around trying to let os
wait for the process group
, but it's still not working. Code below:
def popenAndCall(onExit, popenArgs):
def runInThread(onExit, popenArgs):
tmppath=popenArgs[-1]
proc = subprocess.Popen(popenArgs, preexec_fn=os.setsid)
pid=proc.pid
gid=os.getpgid(pid)
#rec=proc.wait()
rec=os.waitid(os.P_PGID, gid, os.WEXITED | os.WSTOPPED)
print('# <runInThread>: rec=', rec, 'pid=',pid, 'gid=',gid)
onExit(tmppath)
os.remove(tmppath)
return
thread = threading.Thread(target=runInThread, args=(onExit, popenArgs))
thread.start()
return thread
I assume this gid=os.getpgid(pid)
gives me the id of the group, and os.waitid()
wait for the group. I also tried os.waitpid(gid, 0)
, didn't work either.
I'm on the right track?
UPDATE:
It seems that for some editors that works, like xed
. vim
and gvim
both fails.