Skip to content

Commit 1e8c5f1

Browse files
committed
Added --plaintext option to command line tools
Now we default to markdown when displaying status messages; the --plaintext option reverts to previous behavior. This switch is used in test_console.py so existing tests will pass; we can add tests in future without --plaintext to test the markdown rendering.
1 parent 8cb294f commit 1e8c5f1

File tree

8 files changed

+72
-45
lines changed

8 files changed

+72
-45
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: Install dependencies
1919
run: |
2020
python -m pip install --upgrade pip
21-
pip install -e ".[test,richtext]"
21+
pip install -e ".[test,richtext,markdown]"
2222
- name: Run tests
2323
run: |
2424
pytest

tests/test_console.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def test_timeline(mock_get, monkeypatch, capsys):
132132
'media_attachments': [],
133133
}])
134134

135-
console.run_command(app, user, 'timeline', ['--once'])
135+
console.run_command(app, user, 'timeline', ['--once', '--plaintext'])
136136

137137
mock_get.assert_called_once_with(app, user, '/api/v1/timelines/home', {'limit': 10})
138138

@@ -175,7 +175,7 @@ def test_timeline_with_re(mock_get, monkeypatch, capsys):
175175
'media_attachments': [],
176176
}])
177177

178-
console.run_command(app, user, 'timeline', ['--once'])
178+
console.run_command(app, user, 'timeline', ['--once', '--plaintext'])
179179

180180
mock_get.assert_called_once_with(app, user, '/api/v1/timelines/home', {'limit': 10})
181181

@@ -237,7 +237,7 @@ def test_thread(mock_get, monkeypatch, capsys):
237237
}),
238238
]
239239

240-
console.run_command(app, user, 'thread', ['111111111111111111'])
240+
console.run_command(app, user, 'thread', ['--plaintext', '111111111111111111'])
241241

242242
calls = [
243243
mock.call(app, user, '/api/v1/statuses/111111111111111111'),
@@ -553,7 +553,7 @@ def test_notifications(mock_get, capsys):
553553
},
554554
}])
555555

556-
console.run_command(app, user, 'notifications', [])
556+
console.run_command(app, user, 'notifications', ['--plaintext'])
557557

558558
mock_get.assert_called_once_with(app, user, '/api/v1/notifications', {'exclude_types[]': [], 'limit': 20})
559559

toot/commands.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ def timeline(app, user, args, generator=None):
5858
items = reversed(items)
5959

6060
statuses = [from_dict(Status, item) for item in items]
61-
print_timeline(statuses)
61+
62+
print_timeline(statuses, render_mode="plaintext" if args.plaintext else "markdown")
6263

6364
if args.once or not sys.stdout.isatty():
6465
break
@@ -71,7 +72,7 @@ def timeline(app, user, args, generator=None):
7172
def status(app, user, args):
7273
status = api.single_status(app, user, args.status_id)
7374
status = from_dict(Status, status)
74-
print_status(status)
75+
print_status(status, render_mode="plaintext" if args.plaintext else "markdown")
7576

7677

7778
def thread(app, user, args):
@@ -87,7 +88,7 @@ def thread(app, user, args):
8788
thread.append(item)
8889

8990
statuses = [from_dict(Status, s) for s in thread]
90-
print_timeline(statuses)
91+
print_timeline(statuses, render_mode="plaintext" if args.plaintext else "markdown")
9192

9293

9394
def post(app, user, args):
@@ -572,7 +573,7 @@ def notifications(app, user, args):
572573
notifications = reversed(notifications)
573574

574575
notifications = [from_dict(Notification, n) for n in notifications]
575-
print_notifications(notifications)
576+
print_notifications(notifications, render_mode="plaintext" if args.plaintext else "markdown")
576577

577578

578579
def tui(app, user, args):

toot/console.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,13 @@ def editor(value):
235235
json_arg = (["--json"], {
236236
"action": "store_true",
237237
"default": False,
238-
"help": "print json instead of plaintext",
238+
"help": "print json instead of standard text",
239+
})
240+
241+
plaintext_arg = (["-pt", "--plaintext"], {
242+
"action": "store_true",
243+
"help": "Render status messages in plaintext, not markdown",
244+
"default": False,
239245
})
240246

241247
# Arguments for selecting a timeline (see `toot.commands.get_timeline_generator`)
@@ -284,6 +290,7 @@ def editor(value):
284290
"default": False,
285291
"help": "Only show the first <count> toots, do not prompt to continue.",
286292
}),
293+
plaintext_arg,
287294
]
288295

289296
timeline_args = common_timeline_args + timeline_and_bookmark_args
@@ -426,7 +433,8 @@ def editor(value):
426433
"action": "store_true",
427434
"default": False,
428435
"help": "Only print mentions",
429-
})
436+
}),
437+
plaintext_arg,
430438
],
431439
require_auth=True,
432440
),
@@ -464,6 +472,7 @@ def editor(value):
464472
(["status_id"], {
465473
"help": "Show thread for toot.",
466474
}),
475+
plaintext_arg,
467476
],
468477
require_auth=True,
469478
),
@@ -474,6 +483,7 @@ def editor(value):
474483
(["status_id"], {
475484
"help": "ID of the status to show.",
476485
}),
486+
plaintext_arg,
477487
],
478488
require_auth=True,
479489
),

toot/output.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ def print_search_results(results):
277277
print_out("<yellow>Nothing found</yellow>")
278278

279279

280-
def print_status(status: Status, width: int = 80):
280+
def print_status(status: Status, width=80, render_mode=""):
281281
status_id = status.id
282282
in_reply_to_id = status.in_reply_to_id
283283
reblogged_by = status.account if status.reblog else None
@@ -299,7 +299,7 @@ def print_status(status: Status, width: int = 80):
299299
f"<yellow>{time}</yellow>",
300300
)
301301

302-
print_html(status.content, width)
302+
print_html(status.content, width, render_mode=render_mode)
303303

304304
if status.media_attachments:
305305
print_out("\nMedia:")
@@ -320,8 +320,8 @@ def print_status(status: Status, width: int = 80):
320320
)
321321

322322

323-
def print_html(text, width=80):
324-
markdown = "\n".join(html_to_text(text, columns=width, highlight_tags=False))
323+
def print_html(text, width=80, render_mode=""):
324+
markdown = "\n".join(html_to_text(text, columns=width, render_mode=render_mode, highlight_tags=False))
325325
print_out("")
326326
print_out(markdown)
327327

@@ -352,10 +352,10 @@ def print_poll(poll: Poll):
352352
print_out(poll_footer)
353353

354354

355-
def print_timeline(items: List[Status], width=100):
355+
def print_timeline(items: List[Status], width=100, render_mode=""):
356356
print_out("─" * width)
357357
for item in items:
358-
print_status(item, width)
358+
print_status(item, width, render_mode=render_mode)
359359
print_out("─" * width)
360360

361361

@@ -367,7 +367,7 @@ def print_timeline(items: List[Status], width=100):
367367
}
368368

369369

370-
def print_notification(notification: Notification, width=100):
370+
def print_notification(notification: Notification, width=100, render_mode=""):
371371
account = f"{notification.account.display_name} @{notification.account.acct}"
372372
msg = notification_msgs.get(notification.type)
373373
if msg is None:
@@ -376,10 +376,10 @@ def print_notification(notification: Notification, width=100):
376376
print_out("─" * width)
377377
print_out(msg.format(account=account))
378378
if notification.status:
379-
print_status(notification.status, width)
379+
print_status(notification.status, width, render_mode=render_mode)
380380

381381

382-
def print_notifications(notifications: List[Notification], width=100):
382+
def print_notifications(notifications: List[Notification], render_mode="", width=100):
383383
for notification in notifications:
384-
print_notification(notification)
384+
print_notification(notification, render_mode=render_mode)
385385
print_out("─" * width)

toot/richtext/__init__.py

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from toot.tui.utils import highlight_hashtags
2-
from toot.utils import html_to_paragraphs
3-
from toot.wcstring import wc_wrap
1+
from toot.exceptions import ConsoleError
2+
from toot.richtext.plaintext import html_to_plaintext
43
from typing import List
54

65
try:
@@ -9,17 +8,8 @@
98

109
except ImportError:
1110
# Fallback to render in plaintext
12-
def html_to_text(html: str, columns=80, highlight_tags=False) -> List:
13-
output = []
14-
first = True
15-
for paragraph in html_to_paragraphs(html):
16-
if not first:
17-
output.append("")
18-
for line in paragraph:
19-
for subline in wc_wrap(line, columns):
20-
if highlight_tags:
21-
output.append(highlight_hashtags(subline))
22-
else:
23-
output.append(subline)
24-
first = False
25-
return output
11+
def html_to_text(html: str, columns=80, render_mode: str = "", highlight_tags=False) -> List:
12+
if render_mode == "markdown":
13+
raise ConsoleError("Can't render as markdown because the pypandoc library is not available.")
14+
15+
return html_to_plaintext(html, columns, highlight_tags)

toot/richtext/markdown.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
from toot.exceptions import ConsoleError
12
from pypandoc import convert_text
3+
from toot.richtext.plaintext import html_to_plaintext
24
from typing import List
35

46

5-
def html_to_text(html: str, columns=80, highlight_tags=False) -> List:
6-
return [convert_text(
7-
html,
8-
format="html",
9-
to="gfm-raw_html",
10-
extra_args=["--wrap=auto", f"--columns={columns}"],
11-
)]
7+
def html_to_text(html: str, columns=80, render_mode: str = "", highlight_tags=False) -> List:
8+
if render_mode == "plaintext":
9+
return html_to_plaintext(html, columns, highlight_tags)
10+
elif render_mode == "markdown" or render_mode == "":
11+
return [convert_text(
12+
html,
13+
format="html",
14+
to="gfm-raw_html",
15+
extra_args=["--wrap=auto", f"--columns={columns}"],
16+
)]
17+
raise ConsoleError("Unknown render mode; specify 'plaintext' or 'markdown'")

toot/richtext/plaintext.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from toot.utils import html_to_paragraphs
2+
from toot.wcstring import wc_wrap
3+
from toot.tui.utils import highlight_hashtags
4+
from typing import List
5+
6+
7+
def html_to_plaintext(html: str, columns=80, highlight_tags=False) -> List:
8+
output = []
9+
first = True
10+
for paragraph in html_to_paragraphs(html):
11+
if not first:
12+
output.append("")
13+
for line in paragraph:
14+
for subline in wc_wrap(line, columns):
15+
if highlight_tags:
16+
output.append(highlight_hashtags(subline))
17+
else:
18+
output.append(subline)
19+
first = False
20+
return output

0 commit comments

Comments
 (0)