Skip to content

Commit

Permalink
Implement composing tweets using an editor
Browse files Browse the repository at this point in the history
fixes #90
  • Loading branch information
ihabunek committed Aug 22, 2019
1 parent 840b2fd commit d21cad8
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 10 deletions.
16 changes: 14 additions & 2 deletions toot/commands.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-

import sys

from toot import api, config
from toot.auth import login_interactive, login_browser_interactive, create_app_interactive
from toot.exceptions import ConsoleError, NotFoundError
from toot.output import (print_out, print_instance, print_account,
print_search_results, print_timeline, print_notifications)
from toot.utils import assert_domain_exists, multiline_input, EOF_KEY
from toot.utils import assert_domain_exists, editor_input, multiline_input, EOF_KEY


def get_timeline_generator(app, user, args):
Expand Down Expand Up @@ -76,9 +78,17 @@ def curses(app, user, args):


def post(app, user, args):
# TODO: this might be achievable, explore options
if args.editor and not sys.stdin.isatty():
raise ConsoleError("Cannot run editor if not in tty.")

if args.media and len(args.media) > 4:
raise ConsoleError("Cannot attach more than 4 files.")

# Read any text that might be piped to stdin
if not args.text and not sys.stdin.isatty():
args.text = sys.stdin.read().rstrip()

if args.media:
media = [_do_upload(app, user, file) for file in args.media]
media_ids = [m["id"] for m in media]
Expand All @@ -89,7 +99,9 @@ def post(app, user, args):
if media and not args.text:
args.text = "\n".join(m['text_url'] for m in media)

if not args.text:
if args.editor:
args.text = editor_input(args.editor, args.text)
elif not args.text:
print_out("Write or paste your toot. Press <yellow>{}</yellow> to post it.".format(EOF_KEY))
args.text = multiline_input()

Expand Down
33 changes: 25 additions & 8 deletions toot/console.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-

import logging
import os
import shutil
import sys
import logging

from argparse import ArgumentParser, FileType, ArgumentTypeError
from collections import namedtuple
Expand Down Expand Up @@ -39,6 +40,21 @@ def timeline_count(value):
return n


def editor(value):
if not value:
raise ArgumentTypeError(
"Editor not specified in --editor option and $EDITOR environment "
"variable not set."
)

# Check editor executable exists
exe = shutil.which(value)
if not exe:
raise ArgumentTypeError(f"Editor `{value}` not found")

return exe


Command = namedtuple("Command", ["name", "description", "require_auth", "arguments"])


Expand Down Expand Up @@ -298,6 +314,13 @@ def timeline_count(value):
"type": language,
"help": "ISO 639-2 language code of the toot, to skip automatic detection",
}),
(["-e", "--editor"], {
"type": editor,
"nargs": "?",
"const": os.getenv("EDITOR", ""), # option given without value
"help": "Specify an editor to compose your toot, "
"defaults to editor defined in $EDITOR env variable.",
}),
],
require_auth=True,
),
Expand Down Expand Up @@ -500,12 +523,6 @@ def main():
filename = os.getenv("TOOT_LOG_FILE")
logging.basicConfig(level=logging.DEBUG, filename=filename)

# If something is piped in, append it to commandline arguments
if not sys.stdin.isatty():
stdin = sys.stdin.read()
if stdin:
sys.argv.append(stdin)

command_name = sys.argv[1] if len(sys.argv) > 1 else None
args = sys.argv[2:]

Expand All @@ -519,5 +536,5 @@ def main():
except (ConsoleError, ApiError) as e:
print_err(str(e))
sys.exit(1)
except KeyboardInterrupt as e:
except KeyboardInterrupt:
pass
26 changes: 26 additions & 0 deletions toot/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import os
import re
import socket
import subprocess
import tempfile
import unicodedata
import warnings

Expand Down Expand Up @@ -88,3 +90,27 @@ def multiline_input():
break

return "\n".join(lines).strip()


EDITOR_INPUT_INSTRUCTIONS = """
# Please enter your toot. Lines starting with '#' will be ignored, and an empty
# message aborts the post.
"""


def editor_input(editor, initial_text):
"""Lets user input text using an editor."""
initial_text = (initial_text or "") + EDITOR_INPUT_INSTRUCTIONS

with tempfile.NamedTemporaryFile() as f:
f.write(initial_text.encode())
f.flush()

subprocess.run([editor, f.name])

f.seek(0)
text = f.read().decode()

lines = text.strip().splitlines()
lines = (l for l in lines if not l.startswith("#"))
return "\n".join(lines)

0 comments on commit d21cad8

Please sign in to comment.