cmd/tempeditor.py

81 lines
2.2 KiB
Python

'''
This program allows you to use your preferred text editor as an intermediate
step in a processing pipeline. The user will use the text editor to edit a temp
file, and when they close the editor the contents of the temp file will be sent
to stdout.
'''
import argparse
import os
import shlex
import subprocess
import sys
import tempfile
from voussoirkit import pipeable
from voussoirkit import subproctools
from voussoirkit import winwhich
class NoEditor(Exception):
pass
class BadStatus(Exception):
pass
def tempeditor(initial_text=None):
editor = os.environ.get('EDITOR')
if not editor:
raise NoEditor('You do not have an EDITOR variable.')
command = shlex.split(editor)
command[0] = winwhich.which(command[0])
file = tempfile.TemporaryFile('r+', encoding='utf-8', prefix='tempeditor-', delete=False)
command.append(file.name)
if initial_text:
file.write(initial_text)
# The text editor may not be allowed to write to the file while Python has
# the file handle, so let's close it and re-open after the user is finished.
file.close()
status = subprocess.check_call(command)
if status == 0:
handle = open(file.name, 'r', encoding='utf-8')
text = handle.read()
handle.close()
try:
os.remove(file.name)
except Exception:
pass
if status == 0:
return text
else:
raise BadStatus(subproctools.format_command(command), status)
def tempeditor_argparse(args):
initial_text = '\n'.join(pipeable.input(args.initial_text)) if args.initial_text else None
try:
text = tempeditor(initial_text=initial_text)
pipeable.output(text)
return 0
except NoEditor as exc:
pipeable.stderr(exc)
return 1
except BadStatus as exc:
pipeable.stderr(f'Command {exc.args[0]} returned status {exc.args[1]}.')
return 1
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--text', dest='initial_text', default=None)
parser.set_defaults(func=tempeditor_argparse)
args = parser.parse_args(argv)
return args.func(args)
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))