Source code for visidata.editor
import os
import sys
import signal
import subprocess
import tempfile
import curses
import visidata
visidata.vd.tstp_signal = None
[docs]class SuspendCurses:
'Context manager to leave windowed mode on enter and restore it on exit.'
def __enter__(self):
if visidata.vd.scrFull:
curses.endwin()
if visidata.vd.tstp_signal:
signal.signal(signal.SIGTSTP, visidata.vd.tstp_signal)
def __exit__(self, exc_type, exc_val, tb):
if visidata.vd.scrFull:
curses.reset_prog_mode()
visidata.vd.scrFull.refresh()
curses.doupdate()
@visidata.VisiData.api
def launchEditor(vd, *args):
'Launch $EDITOR with *args* as arguments.'
editor = os.environ.get('EDITOR') or vd.fail('$EDITOR not set')
args = editor.split() + list(args)
with SuspendCurses():
return subprocess.call(args)
@visidata.VisiData.api
def launchBrowser(vd, *args):
'Launch $BROWSER with *args* as arguments.'
browser = os.environ.get('BROWSER') or vd.fail('no $BROWSER for %s' % args[0])
vd.status('opening ' + args[0])
args = [browser] + list(args)
subprocess.call(args)
@visidata.VisiData.api
def launchExternalEditor(vd, v, linenum=0):
'Launch $EDITOR to edit string *v* starting on line *linenum*.'
import tempfile
with tempfile.NamedTemporaryFile() as temp:
temp.close() #2118 must close before re-opening on windows
with open(temp.name, 'w') as fp:
fp.write(v)
return vd.launchExternalEditorPath(visidata.Path(temp.name), linenum)
@visidata.VisiData.api
def launchExternalEditorPath(vd, path, linenum=0):
'Launch $EDITOR to edit *path* starting on line *linenum*.'
if linenum:
visidata.vd.launchEditor(path, '+%s' % linenum)
else:
visidata.vd.launchEditor(path)
with open(path, 'r') as fp:
try:
return fp.read().rstrip('\n') # trim inevitable trailing newlines
except Exception as e:
visidata.vd.exceptionCaught(e)
return ''
@visidata.VisiData.api
def suspend(vd):
import signal
with SuspendCurses():
os.kill(os.getpid(), signal.SIGSTOP)
def _breakpoint(*args, **kwargs):
import pdb
class VisiDataPdb(pdb.Pdb):
def precmd(self, line):
r = super().precmd(line)
if not r:
SuspendCurses.__exit__(None, None, None, None)
return r
def postcmd(self, stop, line):
if stop:
SuspendCurses.__enter__(None)
return super().postcmd(stop, line)
SuspendCurses.__enter__(None)
VisiDataPdb(nosigint=True).set_trace()
sys.breakpointhook = _breakpoint
visidata.BaseSheet.addCommand('^Z', 'suspend', 'suspend()', 'suspend VisiData process')
visidata.BaseSheet.addCommand('', 'breakpoint', 'breakpoint()', 'drop into pdb REPL')
visidata.vd.addGlobals(SuspendCurses=SuspendCurses)