Reverse the ordering of the message threads.
Implements: https://todo.sr.ht/~rjarry/aerc/54
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Add reverse-thread-order option to the ui config to enable reverse
display of the mesage threads. Default order is the the intial message
is on the top with all the replies being displayed below. The reverse
options will put the initial message at the bottom with the replies on
top.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Reverse the order of the messages in the message list. The complexity of
reversing the order is abstracted away by the iterators. To reverse the
message list, add the following to your aerc.conf:
[ui]
reverse-msglist-order=true
Thanks to |cos| for sharing his initial implementation of reversing the
order in the message list [0].
[0]: https://git.netizen.se/aerc/commit/?h=topic/asc_sort_imap
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Implement horizontal scrolling for selected lines that are longer than
dialog width. The following keys can be used:
Ctrl-a, Home jump to beginning of line
Ctrl-e, End jump to end of line
Left move one character back
Right move one character forward
Ctrl+b move one word back
Ctrl+w move one word forward
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The [v]split command panics when it is run with no message selected, or
when messages aren't loaded. Check for a valid selected message before
creating a split, and report an error if one isn't selected.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The helpClose function is used to call UpdateScreen on MessageViewer,
which has the effect of invalidating and redrawing the message view.
This logic is redundant with the addition of tcell-term and the main
event loop.
Remove the helpClose calls. Remove the UpdateScreen methods from
messageviewer: those functions are only used by the helpClose function.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Koni Marti <koni.marti@gmail.com>
The terminal widget reports if the cursor should be displayed. Properly
handle this output to report cursor display back to aerc.
Reported-by: staceee
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The ThisDayTimeFormat and friends are missing from the message view
which just uses the message list's default setting. This might not be
desirable since the amount of space available is different. Introduce
separate settings for formatting dates in the message view.
Signed-off-by: Bence Ferdinandy <bence@ferdinandy.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Add :split and :vsplit commands, which split the message list view to
include a message viewer. Each command takes an int, or a delta value
("+1", "-1"). The int value is the resulting size of the message list,
and a new message viewer will be displayed below / to the right of the
message list. This viewer *does not* set seen flags.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Refactor the filtering and paging logic to use several fewer goroutines.
Fixes data race condition with the timing of filter -> pager ->
terminal, can be found when switching message views fast.
Check if filter -> pager process is currently running before calling it
to start again. Fixes data race between fetching message body and
terminal starting. Both can initiate the copying process, and for long
running filters and fast message fetching, it is possible to have
fetched a message but still be running the filter when the terminal
starts.
Move StripAnsi to it's own file in lib/parse, similar to the hyperlinks
parser.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Prevent the embarrassing forgotten attachment scenario by warning the
user before sending a message that may need an attachment but does not
have one. Whether a message needs an attachment is determined by testing
a configurable regex against the message body.
Signed-off-by: Jason Cox <dev@jasoncarloscox.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Fix out-of-bounds panic by updating the focused int variable when
headers change in the switch-account commands.
Fixes: d371c1ac8 ("commands: add switch-account command for composer")
Reported-by: Bence Ferdinandy <bence@ferdinandy.com>
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Export AERC_MIME_TYPE and AERC_FILENAME in the filters command
environment. This allows dynamic coloring with tools that require
a filename and/or a mime type to determine the syntax.
Update docs and add example use in the default config file.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
To allow referencing built-in filters without hard coding a path during
installation, append the following folders to the exec PATH when running
the filter commands:
~/.config/aerc/filters
~/.local/share/aerc/filters
$PREFIX/share/aerc/filters
/usr/share/aerc/filters
If a filter script has the same name than a command in the default exec
PATH, it will not shadow it. In that edge case, the absolute path to the
filter script must be specified.
Suggested-by: Teo Luppi <me@luppi.uk>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
The MouseEvent method of the composer passes on the mouse event to it's
underlying grid while the composer is locked. The underlying grid then
passes on the mouse event to child objects of the grid, which are
referenced via fields of the composer (c.editor is a field in composer
but a child of c.grid, for example). When the grid attempts to pass on
the mouse event, it is referencing a pointer which is locked, and a
deadlock occurs due to the original lock in composer.MouseEvent.
Unlock before calling the grid.MouseEvent, and lock the composer again
after it is called.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Some programs like Skanpage allow sharing files via email and attaching
them automatically from the mailto: link.
This patch introduces parsing of the attach query argument in mailto
links and attaches the listed files.
A potential file:// URL has it's prefix removed.
Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
Remove invalidatable type and all associated calls. All items can
directly invalidate the UI.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
AddEditor acquires the lock and calls FocusEditor which also attempts to
acquire it. Since the lock is not re-entrant, it ends in deadlock.
Add an internal focusEditor fonction that does not acquire the lock.
Fixes: bf2bf8c242 ("compose: prevent out of bounds access")
Reported-by: Moritz Poldrack <moritz@poldrack.dev>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Thomas Vigouroux <thomas.vigouroux@protonmail.com>
The algorithm is broken, there may be more than one header editor with
focused=true. Reset the focused flag before forwarding the mouse event
to the composer grid.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Bence Ferdinandy <bence@ferdinandy.com>
The terminal widget uses it's own redraw logic to improve performance.
With the addition of a main event loop, the redraw logic can happen in
the main loop via the standard Invalidate logic.
Use the Invalidate method to mark aerc invalid, and immediately trigger
a redraw with ui.QueueRedraw. The follow up call to QueueRedraw is
needed because the terminal update happens in a separate goroutine. This
can result in the main event loop finishing it's process of the current
event, redrawing the screen, and the terminal having additional updates
to be drawn.
This fixes race conditions by drawing and calling screen.Show in a
separate goroutine.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Combine tcell events with WorkerMessages to better synchronize state
with IO and UI. Remove Tick loop for rendering. Use events to trigger
renders.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The MouseEvent locks the composer, and also calls FocusEditor which
attempts to lock the composer. This results in a deadlock.
No need to call FocusEditor which takes a name as parameter and needs to
iterate over all editors to find the correct one. We already have the
headerEditor object, use it directly.
Fixes: bf2bf8c242 ("compose: prevent out of bounds access")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Add option to open a message in the message viewer without setting the
seen flag. Enables the message viewer to be used as a preview pane
without changing the message flags unintentionally. Before, the message
viewer would set the seen flag by default. The IMAP backend will now
always fetch the message body with the peek option enabled (same as we
fetch the headers).
An "auto-mark-read" option is added to the ui config which is set to
true by default. If set the false, the seen flag is not set by the
message viewer.
Co-authored-by: "James Cook" <falsifian@falsifian.org>
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
When checking for an exKey, aerc inspects the key and the rune of the
event vs the exkey binding. Runes should only be inspected if the key is
a tcell.KeyRune. Some Ctrl-[:alpha:] keys report a rune in tcell, but
aerc does not have these bound to the keystroke definition. Only <C-x>
has a rune bound, and is one of the very few <C-> keys that can actually
be bound to exKey
Only compare the Rune field if the key is of type KeyRune. Otherwise,
compare the Key. Also compare any modifiers with the keystroke/key
event. These changes allow for any control or alt key combination to be
bound to the exkey.
Update documentaiton to reflect that the default keybind is ':', and not
<semicolon>
Fixes: https://todo.sr.ht/~rjarry/aerc/67
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Subsitute the format specifier %w for %v in the logging facility. The
logging functions use a fmt.Sprintf call behind the scene which does not
recognize %w. %w should be used in fmt.Errorf when you want to wrap
errors. Hence, the log entries that use %w are improperly formatted like
this:
ERROR 2022/10/02 09:13:57.724529 worker.go:439: could not get message
info %!w(*fmt.wrapError=&{could not get structure: [snip] })
^
Links: https://go.dev/blog/go1.13-errors
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
Upgrade tcell-term to v0.2.0
Use Start method from tcell-term. This prevents aerc from needing to
wait until the command has started to continue. The tcell-term start
method blocks until the command is started, similar to cmd.Start. By
doing so, we prevent a race condition between aerc and tcell-term on
access to cmd.Process.
Remove cleanup of cmd, this is all already handled by tcell-term when
Close is called.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The terminal widget has two invalidation methods, one exported and one
private. The private one does nothing special.
Remove the private method and only use the exported method.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Pass message containing remaining directories to check. Account widget
will recursively call CheckMail with the remaining directories until
a Done message is returned.
Only needed for IMAP worker as other workers run check-mail-cmd in
a separate goroutine.
Suggested-By: Tim Culverhouse <tim@timculverhouse.com>
Signed-off-by: kt programs <ktprograms@gmail.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
Fix the following panic, seen while switching accounts:
runtime error: index out of range [4] with length 4
goroutine 6 [running]:
git.sr.ht/~rjarry/aerc/widgets.(*Composer).Focus(0xc005cfbe30?, 0x40?)
git.sr.ht/~rjarry/aerc/widgets/compose.go:618 +0x51
git.sr.ht/~rjarry/aerc/widgets.(*Aerc).focus(0xc00034c000, {0x0?, 0x0})
git.sr.ht/~rjarry/aerc/widgets/aerc.go:568 +0xec
git.sr.ht/~rjarry/aerc/widgets.(*Aerc).BeginExCommand.func2()
git.sr.ht/~rjarry/aerc/widgets/aerc.go:590 +0x4c
git.sr.ht/~rjarry/aerc/widgets.(*ExLine).Event(0xc009453860, {0xbb6820?, 0xc009baa320?})
git.sr.ht/~rjarry/aerc/widgets/exline.go:81 +0xbc
git.sr.ht/~rjarry/aerc/widgets.(*Aerc).Event(0xc009ab1950?, {0xbb6820?, 0xc009baa320?})
git.sr.ht/~rjarry/aerc/widgets/aerc.go:285 +0x470
git.sr.ht/~rjarry/aerc/lib/ui.(*UI).ProcessEvents(0xc000327540)
git.sr.ht/~rjarry/aerc/lib/ui/ui.go:117 +0x202
created by main.main
git.sr.ht/~rjarry/aerc/aerc.go:244 +0x94c
Protect Composer.editable and Composer.focus with a mutex.
Reported-by: Bence Ferdinandy <bence@ferdinandy.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
Moves logic for creating dynamic folders from the dirlist widget to the
backend. Since dynamic folders are notmuch-specific, the notmuch backend
should be responsible for correctly setting up those folders. It does
that by sending two DirectoryInfos: the first to create the message
store, the second to fetch the directory content.
This approach also fixes a deadlock introduced by 716ade8968
("worker: lock access to callback maps").
Reported-by: Bence Ferdinandy <bence@ferdinandy.com>
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
The exline widget works by matching actual keystrokes to a map of
keybinds, and if a match is found sending simulated keystrokes through
aerc. This has the effect of aerc thinking we are actually typing in the
expanded command, and aerc attempts to draw the completions. This
results in even basic navigation having two screen draws:
For example, pressing 'j' to select the next message (:next), draws once
for the initial key event and state change, and again after the
completion debounce timer.
Disable tab completion while aerc is simulating keystrokes. If the
exline still has focus after simulating keystrokes, restore tab
completion.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Koni Marti <koni.marti@gmail.com>
A data race exists between the timer goroutine and the main goroutine
for checking / setting the status of acct.checkingmail. Protect access
to this value with a mutex
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
If a :term is open and aerc is focused on another tab, it is possible
for the :term to redraw itself to the screen.
Only allow terminal to redraw itself when it is focused.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The grid method Children returns the children of a grid, and is never
used. The function is reimplemented in both aerc.go and account.go, also
never called.
Remove these unused methods.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The dirlist is invalidated explicitly after the spinner is stopped.
For simplicitly, don't invalidate on spinner.Invalidate.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Allow switching to next or previous account with switch-account -n and
switch-account -p, respectively. By default, these are bound to Alt-n
and Alt-p.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Koni Marti <koni.marti@gmail.com>
Extract some functionality of the composer constructor into a
account-specific setup function that can be used to implement account
switching.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
There is a race between PartViewer.Cleanup and PartViewer.Draw. pv.term
may be not nil in Draw and Cleanup() may set it to nil before
pv.term.Draw() is called, causing an invalid memory access:
[signal SIGSEGV: segmentation violation code=0x1 addr=0x29 pc=0x9413b8]
git.sr.ht/~rjarry/aerc/widgets.(*Terminal).Draw(0x0?, 0x0?)
git.sr.ht/~rjarry/aerc/widgets/terminal.go:97 +0x18
git.sr.ht/~rjarry/aerc/widgets.(*PartViewer).Draw(0xc00012a540, 0xc0026ea690)
git.sr.ht/~rjarry/aerc/widgets/msgviewer.go:862 +0x2fd
There is no need to reset term to nil.
Fixes: 77f69501d6 ("msgviewer: properly close embedded terminal")
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
The terminal widget uses it's own internal event handler to redraw
itself for improved performance. The event handler draws, updates the
screen, and invalidates. The last invalidate is redundant: Invalidating
has the result of telling aerc to redraw the screen. A race condition
can occur where an event is emitted from the terminal and the terminal
is closed before the event is handled. This results in handling the
event after the terminal is closed, and a panic:
panic: Attempted to invalidate unknown cell
goroutine 54685 [running]:
git.sr.ht/~rjarry/aerc/lib/ui.(*Grid).cellInvalidated(0xc00b0a34a0, {0xbb8f10?, 0xc00360cd80})
git.sr.ht/~rjarry/aerc/lib/ui/grid.go:287 +0x175
git.sr.ht/~rjarry/aerc/lib/ui.(*Invalidatable).DoInvalidate(0xc0002e7900?, {0xbb8f10?, 0xc00360cd80?})
git.sr.ht/~rjarry/aerc/lib/ui/invalidatable.go:22 +0x82
git.sr.ht/~rjarry/aerc/widgets.(*Terminal).invalidate(...)
git.sr.ht/~rjarry/aerc/widgets/terminal.go:93
git.sr.ht/~rjarry/aerc/widgets.(*Terminal).HandleEvent(0xc00360cd80, {0xbb4ba0?, 0xc006022690?})
git.sr.ht/~rjarry/aerc/widgets/terminal.go:192 +0xd2
github.com/gdamore/tcell/v2/views.(*WidgetWatchers).PostEvent(...)
github.com/gdamore/tcell/v2@v2.5.3/views/widget.go:113
github.com/gdamore/tcell/v2/views.(*WidgetWatchers).PostEventWidgetContent(0xc0001b9360, {0xbbc950?, 0xc0001b9320})
github.com/gdamore/tcell/v2@v2.5.3/views/widget.go:123 +0x12b
git.sr.ht/~rockorager/tcell-term.(*Terminal).run.func1()
git.sr.ht/~rockorager/tcell-term@v0.1.0/terminal.go:117 +0x9d
created by git.sr.ht/~rockorager/tcell-term.(*Terminal).run
git.sr.ht/~rockorager/tcell-term@v0.1.0/terminal.go:104 +0x110
Don't invalidate on EventWidgetContent. The terminal already handles
drawing and updating the tcell Screen internally.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
A race condition can occur when a PartViewer is closing and also working
on a draw. The closing process sets the terminal to nil, which will
create a panic. This can be tested in development by setting the timer
in the main aerc tick loop to something very low (1 ms for example).
One other unprotected call to terminal exists in the composer widget.
Check that the terminal is not nil before calling methods on it.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Improve terminal mouse support by forwarding mouse events to the
terminal widget. Clicking and dragging are supported.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
The terminal widget already handles most boring stuff: unwatch terminal
events, kill the underlying process, wait for it to exit, etc. Call the
Close() method and be done with it.
This avoids issues where the embedded terminal widget is destroyed but
the pager process does not know about it and dies in agony, writing over
aerc's UI:
Vim: Caught deadly signal HUP
Also, it may avoid leaving child processes as zombies without giving
them a proper burial.
Reported-by: skejg
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
The terminal widget internally uses several context methods. Check that
context is not nil before calling any method to prevent panics.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Allow forwarding paste events to embedded applications. When a bracketed
paste is in progress, do not process any command bindings.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>