diff options
author | Anton Khirnov <anton@khirnov.net> | 2021-01-17 13:18:15 +0100 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2021-01-17 13:18:15 +0100 |
commit | 8f0f494ab0e621573eb6f941663891119b5c555b (patch) | |
tree | d9e70cbd47895c5dd7774402b4533235ccefefe6 | |
parent | aafbf031108a1328671deb658bf7d220d3e42f8b (diff) |
widgets/thread: allow forcing inline display of selected attachment types
-rw-r--r-- | alot/defaults/alot.rc.spec | 4 | ||||
-rw-r--r-- | alot/widgets/thread.py | 53 |
2 files changed, 44 insertions, 13 deletions
diff --git a/alot/defaults/alot.rc.spec b/alot/defaults/alot.rc.spec index 46572758..d2b7866c 100644 --- a/alot/defaults/alot.rc.spec +++ b/alot/defaults/alot.rc.spec @@ -81,6 +81,10 @@ thread_authors_order_by = option('first_message', 'latest_message', default='fir # number of characters used to indent replies relative to original messages in thread mode thread_indent_replies = integer(default=2) +# list of MIME types to always render inline, even when Content-Disposition +# designates them attachments +thread_force_inline_mimetypes = force_list(default = list(text/*)) + # set terminal command used for spawning shell commands terminal_cmd = string(default='x-terminal-emulator -e') diff --git a/alot/widgets/thread.py b/alot/widgets/thread.py index 455815f4..8f07432e 100644 --- a/alot/widgets/thread.py +++ b/alot/widgets/thread.py @@ -97,7 +97,7 @@ class _MIMEPartWidget(urwid.WidgetWrap): c.cycle_alt() class _CryptPartWidget(_MIMEPartWidget): - def __init__(self, mime_tree, alternative_pref): + def __init__(self, mime_tree, alternative_pref, force_inline_types): children = None # handle broken crypto parts where we could not get the payload @@ -138,7 +138,7 @@ class _CryptPartWidget(_MIMEPartWidget): text_parts.append('crypto processing error: ' + mime_tree.crypt_error) attr_name = 'crypt_invalid' - child = _render_mime_tree(mime_tree.children[0], alternative_pref) \ + child = _render_mime_tree(mime_tree.children[0], alternative_pref, force_inline_types) \ or _EmptyPartWidget() attr = settings.get_theming_attribute('thread', attr_name) body_wgt = urwid.AttrMap(urwid.LineBox(child, title = ':'.join(text_parts)), attr) @@ -247,6 +247,8 @@ class _TextPart(_MIMEPartWidget): _QUOTE_CHARS = '>|:}#' _QUOTE_REGEX = '(([ \t]*[{quote_chars}])+)'.format(quote_chars = _QUOTE_CHARS) + _body_placeholder = None + _max_level = None _lines = None _fold = None @@ -282,7 +284,20 @@ class _TextPart(_MIMEPartWidget): self._lines, self._fold, self._max_level = \ self._parse_quotes(text, attr_text, attrs_quote) - super().__init__(urwid.Text('')) + self._body_placeholder = urwid.WidgetPlaceholder(urwid.Text('')) + + # decorate inline-forced attachments with a linebox + if part.attachment: + title = 'attachment %s' % part.content_type + fname = part.attachment.get_filename() + if fname: + title += ': %s' % fname + + wgt = urwid.LineBox(self._body_placeholder, title = title) + else: + wgt = self._body_placeholder + + super().__init__(wgt) def _parse_quotes(self, text, attr_text, attrs_quote): """ @@ -385,7 +400,7 @@ class _TextPart(_MIMEPartWidget): self._fold_context) if len(markup_lines) == 0: markup_lines = [''] - self._w = urwid.Text(markup_lines) + self._body_placeholder.original_widget = urwid.Text(markup_lines) self._fold_level = val class _EmptyPartWidget(_MIMEPartWidget): @@ -393,10 +408,10 @@ class _EmptyPartWidget(_MIMEPartWidget): body_wgt = urwid.Text('<<< No displayable content >>>', align = 'center') super().__init__(body_wgt) -def _handle_multipart(mime_tree, alternative_pref): +def _handle_multipart(mime_tree, alternative_pref, force_inline_types): children = [] for child in mime_tree.children: - ch = _render_mime_tree(child, alternative_pref) + ch = _render_mime_tree(child, alternative_pref, force_inline_types) if ch is not None and not isinstance(ch, _EmptyPartWidget): children.append(ch) @@ -408,19 +423,30 @@ def _handle_multipart(mime_tree, alternative_pref): return _MultiAltWidget(children, mime_tree.children, alternative_pref) return _MultiMixedWidget(children) -def _render_mime_tree(mime_tree, alternative_pref): +def _render_mime_tree(mime_tree, alternative_pref, force_inline_types): # handle encrypted/signed parts if mime_tree.is_signed or mime_tree.is_encrypted: - return _CryptPartWidget(mime_tree, alternative_pref) + return _CryptPartWidget(mime_tree, alternative_pref, force_inline_types) if mime_tree.children is not None: # multipart MIME parts - return _handle_multipart(mime_tree, alternative_pref) + return _handle_multipart(mime_tree, alternative_pref, force_inline_types) - # no children - this is a leaf node - # skip attachment parts + ## no children - this is a leaf node + # skip attachment parts, unless they are of a user-specified type if mime_tree.attachment: - return None + force_inline = False + + for t in force_inline_types: + maintype, _, subtype = t.partition('/') + + if (maintype == mime_tree.content_maintype and + (subtype == mime_tree.content_subtype or subtype == '*')): + force_inline = True + break + + if not force_inline: + return None # try rendering the message text = mime_tree.render_str() @@ -533,6 +559,7 @@ class MessageWidget(urwid.WidgetWrap): """ self._message = message + force_inline_types = settings.get('thread_force_inline_mimetypes') if settings.get('prefer_plaintext'): alternative_pref = 'text/plain' else: @@ -542,7 +569,7 @@ class MessageWidget(urwid.WidgetWrap): self._source_wgt = _RawMessageWidget(message.as_bytes()) self._attach_wgt = self._get_attachments() - self._body_wgt = _render_mime_tree(message.body, alternative_pref) + self._body_wgt = _render_mime_tree(message.body, alternative_pref, force_inline_types) if self._body_wgt is None: self._body_wgt = _EmptyPartWidget() |