cmd/tempeditor.py

82 lines
2.2 KiB
Python
Raw Normal View History

2021-01-18 20:51:04 +00:00
'''
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.
'''
2020-12-09 15:20:26 +00:00
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:]))