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>
Replace go-libvterm package with tcell-term. go-libvterm provides the
embedded terminal for aerc. It uses a statically linked C library,
requiring CGO.
tcell-term is written in pure go and is written to be portable with
tcell applications by implementing the tcell Widget interface. This
allows the terminal to take a view (which aerc already supplies) and
draw directly to it, as well as issue tcell Events to a Watcher.
Enable setting cursor shapes in embedded terminals.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Now that tcell events are handled in a goroutine, no need for a channel
to buffer them.
Rename ui.Tick() to ui.Render() and ui.Run() to ui.ProcessEvents() to
better reflect what these functions do.
Move screen.PollEvent() into ui.ProcessEvents(). Register the panic
handler in ui.ProcessEvents().
Remove aerc.ui.Tick() from DecryptKeys(). What the hell was that?
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
Some people are worried that they might leak their timezone and wish to
send their mails with the Date header in UTC. For this a new key is
added to the account sections to enforce sending in UTC instead of the
system's timezone.
Suggested-by: "Ricardo Correia" <aerc-lists.sr.ht@wizy.org>
Thanks: to Ricardo for checking and correcting my incorrect assertions
Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
Enable the use of MoveMessages worker messages from the UI to the
backend. Completes implemention of MoveMessages for all supported
backends.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Improve cursor re-positioning while filtering with and without threads.
Reposition cursor in client-side threading mode with a callback that is
set during store.NextPrev(). Run callback when the threads are
constructed in order to reposition the cursor correctly. The callback is
deactivated when store.Select() is called.
Steps to reproduce two issues:
* Reproduce issue 1:
1. Activate client-side threading
2. Apply a filter, e.g. :filter -f Koni
3. Move cursor around so that a message is highlighted
4. clear filter with :clear
5. The cursor is expected to remain on the selected message but is
actually not
* Reproduce issue 2:
1. Activate client-side threading
2. Go the end of the message list
2. Apply a filter, e.g. :filter -f Koni
5. The cursor is now at the end of the filtered results instead of at
the beginning
This patch fixes both of those issues. Tested in regular and threaded
view according to the following check list (expected behavior in
parenthesis):
1. Apply filter from a message that remains in the filter (cursor on message,
message selected)
2. Apply filter from a message that will not remain (cursor at the top,
no message selected)
3. Clear filter (cursor remains on message, message selected)
4. Scroll line-by-line (threads: cursor remains on line, does not "jump"
with message)
5. Search (cursor on first result)
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
Fix the following errors:
widgets/dirtree.go:401:18: not enough arguments in call to dt.UiConfig
have ()
want (string) (typecheck)
if dt.UiConfig().DirListCollapse != 0 {
^
widgets/dirtree.go:402:38: not enough arguments in call to dt.UiConfig
have ()
want (string) (typecheck)
node.Hidden = depth > dt.UiConfig().DirListCollapse
^
Since commit e0b62db583c3 ("fix: Set proper UIConfig for msgstores"),
DirectoryTree.UiConfig() takes a path parameter.
Fixes: db39ca181a ("dirtree: add dirtree-collapse config setting")
Signed-off-by: Robin Jarry <robin@jarry.cc>
Adds a setting to the configuration to choose at which level the
folders in the dirtree are collapsed by default.
In my case, this is useful because my organisation has some rather deep
nesting in the folder structure, and a _lot_ of folders, and this way I
can keep my dirtree uncluttered while still having all folders there if
I need them.
Signed-off-by: Sijmen <me@sijman.nl>
Acked-by: Koni Marti <koni.marti@gmail.com>
The merged UIConfig used to create new message stores is based on the
selected directory. If the message store is created by other means than
selecting (ListDirectories for maildir/notmuch/mbox, or check-mail) it
may have an incorrect configuration if the user has folder-specific
values for:
- Threaded view
- Client built threads
- Client threads delay
- Sort criteria
- NewMessage bell
Use the correct merged UIConfig when creating a new message store.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Separate the marking functions from the message store and extract the
marking behavior into its own class with tests.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Warn users that the passwords are stored as plaintext. Add
recommmendation to use personal password store.
Implements: https://todo.sr.ht/~rjarry/aerc/39
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Show contextual keybinds in a textbox when using the ':help keys'
command. This command is bound to '?' by default.
Fixes: https://todo.sr.ht/~rjarry/aerc/42
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Implement a scrollable text box that displays a list of strings which
can be filtered. The widget is closed by pressing ESC or ENTER. If ENTER
is pressed and an entry has been selected, this text will be passed to
the closing callback.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Implement an interface for aerc's dialog implementation. Provide dialogs
the ability to set their own height and width of their drawing context.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Since the minimum required version of Go has been bumped to 1.16, the
deprecation of io/ioutil can now be acted upon. This Commit removes the
remaining dependencies on ioutil and replaces them with their io or os
counterparts.
Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
Error wrapping as introduced in Go 1.13 adds some additional logic to
use for comparing errors and adding information to it.
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
Apply GoDoc comment policy (comments for humans should have a space
after the //; machine-readable comments shouldn't)
Use strings.ReplaceAll instead of strings.Replace when appropriate
Remove if/else chains by replacing them with switches
Use short assignment/increment notation
Replace single case switches with if statements
Combine else and if when appropriate
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
Replaces infinite for loops containing a select on a channel with a
single case with a range over the channel.
Removes redundant assignments to blank identifiers.
Remove unnecessary guard clause around delete().
Remove `if condition { return true } return false` with return condition
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
Specify an account parameter in the mailto argument. If not specified,
the selected account is used as default.
Example:
$ aerc 'mailto:user@host?account=Fastmail'
Suggested-by: staceee
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Add :check-mail command for ad-hoc checking of mail. Reset timer for
automatic checking if it is enabled.
Suggested-by: staceee
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This can be useful in cases when:
1. outgoing-cred-cmd requires a user action or confirmation (e.g. when
using pass with a Yubikey or similar smart card that requires a user
to enter a pin or touch the device when decrypting the password)
2. A user starts aerc frequently, but not all the sessions end up with
sending emails
3. So the user only wants to execute outgoing-cred-cmd when the password
is really used, so the user doesn't have to enter pin or touch their
Yubikey each time aerc starts
Signed-off-by: Stas Rudakou <stas@garage22.net>
Acked-by: Robin Jarry <robin@jarry.cc>
Client-side thread debouncing happens in a different goroutine. Any
function or variable that is called or accessed by this goroutine should
be protected from a concurrent access.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Debounce client-side thread building in the message store. Debouncing is
useful when multiple messages are loaded, i.e. when scrolling with
PgUp/PgDown.
Without the debouncing, all client-side threads will be built everytime
the message store is updated which creates a noticable lag in the
message list ui when client-side threading is activated.
The default debouncing delay can be changed by changing
'client-threads-delay' in the UI config section.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
check-mail was triggered to run at startup after a Done:FetchHeaders
message. This message would only occur if there were messages in the
default folder. In the case where there are no messages, check-mail
would not run at startup as intended. Run check-mail even if there are
no messages found in the default folder at startup.
Fixes: https://todo.sr.ht/~rjarry/aerc/60
Reported-by: ~foutrelis
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Change the message store architecture from an index-based to a uid-based
one. Key advantage of this design approach is that no reselect mechanism
is required anymore since it comes with the design for free.
Fixes: https://todo.sr.ht/~rjarry/aerc/43
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This prevents dereferencing nil when updating RUE counts. This seems to
happen for messages that were not yet loaded, but were selected for
copy operation. This can happen when using `mark -a` command and then
initiating copy operation.
When such message is encountered during RUE counting, it is stopped
and full recount is triggered.
**Original backtrace:**
Error: runtime error: invalid memory address or nil pointer dereference
goroutine 1 [running]:
runtime/debug.Stack()
runtime/debug/stack.go:24 +0x65
git.sr.ht/~rjarry/aerc/logging.PanicHandler()
git.sr.ht/~rjarry/aerc/logging/panic-logger.go:45 +0x64b
panic({0x9e5f80, 0xecc360})
runtime/panic.go:844 +0x258
git.sr.ht/~rjarry/aerc/widgets.(*AccountView).onMessage(0xc0001be870, {0xb7f860?, 0xc00073b4c0?})
git.sr.ht/~rjarry/aerc/widgets/account.go:353 +0xecc
git.sr.ht/~rjarry/aerc/widgets.(*AccountView).Tick(0xc0001be870)
git.sr.ht/~rjarry/aerc/widgets/account.go:116 +0x6c
git.sr.ht/~rjarry/aerc/widgets.(*Aerc).Tick(0xc0003ba000)
git.sr.ht/~rjarry/aerc/widgets/aerc.go:144 +0x7a
main.main()
git.sr.ht/~rjarry/aerc/aerc.go:225 +0xbb8
Signed-off-by: Ensar Sarajčić <dev@ensarsarajcic.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Do not pass logger objects around anymore. Shuffle some messages to make
them consistent with the new logging API. Avoid using %v when a more
specific verb exists for the argument types.
The loggers are completely disabled (i.e. Sprintf is not even called)
by default. They are only enabled when redirecting stdout to a file.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
The Tabs object exposes an array of Tab objects and the current selected
index in that array. The these two fields are sometimes modified in
goroutines, which can lead to data races causing fatal out of bounds
accesses on the tab array.
Hide these fields as private API. Expose only what needs to be seen from
the outside. This will prepare for protecting concurrent access with
a lock in the next commit.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Koni Marti <koni.marti@gmail.com>