co- Properly split addresses into name and email
- Deal with them as (name, email) tuples
internally, as a (quoted) name can contain a comma
- Format them properly again when inserting into the message
Fixes#75
With a trivial "/, Enter", Dodo crashes with:
Error: notmuch search requires at least one search term.
Traceback (most recent call last):
[...]
File ".../dodo/search.py", line 54, in refresh
self.d = json.loads(self.json_str)
^^^^^^^^^^^^^^^^^^^^^^^^^
[...]
File "/usr/lib/python3.12/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Given that only an empty search should be able to trigger such an error,
it seems sensible for an enter press without input to just close the command bar
again.
See https://docs.python.org/3/library/re.html#raw-string-notation
Even if those patterns do not contain any backslashes, it is a good practice to
use raw strings for all regex patterns, to avoid footguns when changing the
patterns in the future.
Also see 93244ad996 where this did already cause a
SyntaxWarning before.
- Fix the stray "f" inside the string breaking the color
- Don't hide the traceback from the user, as it's impossibe to track down issues
without it ("exception: None"?!)
- HTML escape the exception message - while somewhat unlikely, it could contain
HTML characters.
- Use stdin instead of a temporary file (needs -T argument to w3m to avoid it
interpreting stdin as plaintext)
- Pass check=True to subprocess.run to raise an exception if w3m fails
- Catch that exception (as well as OSError, e.g. w3m not installed or not
executable) and show an error instead of crashing dodo
Collapsing causes the scroll position to be reset, which the reselecting
will restore. As a bonus, it seems the framework is smart enough to not
move the scroll position *at all* since both operations are presumably
done within one rendering pass.
It will still snap back to the selected message if the user happened to
have scrolled to a position where it wasn't visible before the sync, but
I still consider this a more sensible behaviour than moving back to the
top.
If I configure my MUA to do regular syncs, I'd expect that first sync to
happen at startup *and then* each $time_period. It's especially painful
when the first sync of the day is a bit long, as both delays compound
while you stare blankly at your stale inbox, waiting for your morning
coffee to kick in.
The default get_content() implementation (and the only available!) will
decode any 'text/*' attachment into a `str`, which means we need to
handle it a bit differently. Since we're at it, we use the charset
specified so that we write out a file as similar as possible to the one
that was actually sent.
Also, use early return pattern to filter out non-attachments.
IMHO, having the full name of the sender is more important than the
email in the message list. However, we can use the new free screen
realestate to display the new subject line if it has changed
Besides the obvious tree-like thing, this has for consequences that the
ordering of messages is slightly different, as they are now
topologically sorted rather than through purely chronological order.
Unless told otherwise, the web engine will default to latin1 for the
contents. Some emails don't specify the encoding in the HTML payload, so
our mangling at that level didn't have any effect.
Using message_from_file will try to force the email into UTF-8, which
can result in exceptions thrown for a perfectly valid email that just
happens to use older encodings.
It avoids parallel refreshes, which can happen if the refresh triggers a
secondary data update, e.g. via automatic mark as read on thread
opening.
It means we trigger our own has_refreshed signal, but that's OK, the
effects should only be a top-level view refresh.
This is a good old breaking change. Now, `current_message` will actually
yield the current message object rather than its index, while said index
is available at `current_index`. All the model APIs are changed to
consume and emit QModelIndex, and said indices are attached the message
they represent at creation, making it easier.
The goal long-term is to be able to move away from the ListView to use a
TreeView instead.
show_message has a weird API that deals in integer indices, and is also
used to refresh the UI. The indices are annoying because they're an
implementation detail, and the refresh part is a bit surprising when you
come across it in the code.
Removing it leaves only `current_message` as the remaining "integer" API
from ThreadPanel.
Rather than explicitly refreshing the data *then* the UI, let's just use
the default model signals to trigger the UI refreshes
This actually saves us a full refresh when first opening a thread.
Irrelevant in the sense that they didn't match the origin search query.
Not all themes have been tested, the values were determined by looking
for the recommended value for code comments on the various colorscheme
homepages.
Any thread opening is normally done from a search query. That search
query might have nothing to do with the unread status, and could only
match a handful of messages in the thread. So, rather than jumping to
the first unread message, we keep the search query as context when
opening the thread and use it to jump to the first message matching it.
When tagging a single message in a thread, only refresh that message
rather than the entire thread.
This is again due to some threads being *very* big, which when combined
with crypto signatures make the UI feel sluggish when changing the state
of a message, e.g. when reading it for the first time.
The computing time now doesn't scale with the size of the thread. It's
at similar levels from before on small threads, and is an order of
magnitude better on the recent tmpfs thread on debian-devel.
Note that right now we go through the entire list to get the index of a
given message. This could easily be optimized later on.