diff --git a/alot/db/message.py b/alot/db/message.py index 6b1a3d9b8..e86dabf78 100644 --- a/alot/db/message.py +++ b/alot/db/message.py @@ -26,7 +26,7 @@ class Message: It it uses a :class:`~alot.db.DBManager` for cached manipulation and lazy lookups. """ - def __init__(self, dbman, msg, thread=None): + def __init__(self, dbman, msg, thread=None, parent=None): """ :param dbman: db manager that is used for further lookups :type dbman: alot.db.DBManager @@ -34,11 +34,15 @@ def __init__(self, dbman, msg, thread=None): :type msg: notmuch2.Message :param thread: this messages thread (will be looked up later if `None`) :type thread: :class:`~alot.db.Thread` or `None` + :param parent: this message's parent (if it was a reply, and we have the + message it was a reply to) + :type parent: :class:`~alot.db.Message` or `None` """ self._dbman = dbman self._id = msg.messageid self._thread_id = msg.threadid self._thread = thread + self._parent = parent try: self._datetime = datetime.fromtimestamp(msg.date) except ValueError: @@ -50,6 +54,11 @@ def __init__(self, dbman, msg, thread=None): self._mime_tree = None # will be read upon first use self._tags = msg.tags + try: + self._subject = decode_header(msg.header('subject')) + except LookupError: # No Subject on Email + self._subject = '' + self._session_keys = [ value for _, value in msg.properties.getall(prefix="session-key", exact=True) @@ -110,6 +119,10 @@ def get_email(self): warning, policy=email.policy.SMTP) return self._email + def get_parent(self): + """returns parent Message if this is a reply or None otherwise""" + return self._parent + def get_date(self): """returns Date header value as :class:`~datetime.datetime`""" return self._datetime @@ -118,6 +131,10 @@ def get_filename(self): """returns absolute path of message files location""" return self._filename + def get_subject(self): + """returns Subject header (str)""" + return self._subject + def get_message_id(self): """returns messages id (str)""" return self._id diff --git a/alot/db/thread.py b/alot/db/thread.py index be91cdf12..ed9bcb0ed 100644 --- a/alot/db/thread.py +++ b/alot/db/thread.py @@ -49,7 +49,7 @@ def _refresh(self, thread): try: first_msg = list(thread.toplevel())[0] subject = first_msg.header('subject') - except IndexError: + except (IndexError, LookupError): subject = '' self._subject = subject @@ -236,11 +236,11 @@ def get_messages(self): if not self._messages: # if not already cached with self._dbman._with_notmuch_thread(self._id) as thread: - def accumulate(acc, msg): - M = Message(self._dbman, msg, thread=self) + def accumulate(acc, msg, parent=None): + M = Message(self._dbman, msg, thread=self, parent=parent) acc[M] = [] for m in msg.replies(): - acc[M].append(accumulate(acc, m)) + acc[M].append(accumulate(acc, m, M)) return M self._messages = {} diff --git a/alot/widgets/thread.py b/alot/widgets/thread.py index c5276df83..b5244fffd 100644 --- a/alot/widgets/thread.py +++ b/alot/widgets/thread.py @@ -78,9 +78,21 @@ def _render_wrap(size, focus=False): def __str__(self): author, address = self.message.get_author() date = self.message.get_datestring() + subject = self.message.get_subject() rep = author if author != '' else address if date is not None: rep += " (%s)" % date + + # Hide Subjects which are replies to the parent message. + # This allows threads containing multiple messages with distinct + # subjects to be displayed without adding noise to the replies. + parent = self.message.get_parent() + if parent: + psubject = parent.get_subject() + subject = subject.replace(psubject, "...") + + rep += ": " + subject + return rep def selectable(self):