cmd/tempeditor.py

100 lines
2.6 KiB
Python
Raw Normal View History

2021-01-18 20:51:04 +00:00
'''
2021-05-13 19:20:19 +00:00
tempeditor
==========
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.
2021-05-13 19:20:19 +00:00
Command line usage:
> tempeditor [--text X]
--text X:
The initial text in the document.
Uses pipeable to support !c clipboard, !i stdin.
If not provided, the user starts with a blank document.
2021-01-18 20:51:04 +00:00
'''
2020-12-09 15:20:26 +00:00
import argparse
import os
import shlex
import subprocess
import sys
import tempfile
2021-05-13 19:20:19 +00:00
from voussoirkit import betterhelp
2020-12-09 15:20:26 +00:00
from voussoirkit import pipeable
from voussoirkit import subproctools
from voussoirkit import winwhich
2021-09-23 06:17:12 +00:00
from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'tempeditor')
2020-12-09 15:20:26 +00:00
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):
if args.initial_text is not None:
initial_text = pipeable.input(args.initial_text, split_lines=False)
2020-12-09 15:20:26 +00:00
try:
2021-09-23 06:17:12 +00:00
text = tempeditor(initial_text=args.initial_text)
pipeable.stdout(text)
2020-12-09 15:20:26 +00:00
return 0
except NoEditor as exc:
2021-09-23 06:17:12 +00:00
log.fatal(exc)
2020-12-09 15:20:26 +00:00
return 1
except BadStatus as exc:
2021-09-23 06:17:12 +00:00
log.fatal(f'Command {exc.args[0]} returned status {exc.args[1]}.')
2020-12-09 15:20:26 +00:00
return 1
2021-09-23 06:17:12 +00:00
@vlogging.main_decorator
2020-12-09 15:20:26 +00:00
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--text', dest='initial_text', default=None)
parser.set_defaults(func=tempeditor_argparse)
2021-05-13 19:20:19 +00:00
return betterhelp.single_main(argv, parser, __doc__)
2020-12-09 15:20:26 +00:00
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))