Commit graph

1469 commits

Author SHA1 Message Date
Koni Marti
0e50f29bf3 notmuch: move logic for dynamic folders to backend
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>
2022-09-29 16:52:12 +02:00
Koni Marti
684ceed2cd lib: parse address header fields to utf-8
When parsing address header fields, the field charset is automatically
decoded to UTF-8. If the charset is unknown, use the raw field value.

Fixes: https://todo.sr.ht/~rjarry/aerc/91
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
2022-09-29 16:51:53 +02:00
Tim Culverhouse
055c6dc660 exline: don't draw completions for keybinds
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>
2022-09-29 16:42:10 +02:00
Koni Marti
75fc42e270 imap: send message info updates for bulk flag ops
Send message info updates back to to ui instead of posting a fetch
header action to the worker when performing a bulk flag operation. This
prevents the worker channels from filling up which can result in a
deadlock.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
2022-09-29 16:41:42 +02:00
Jason Stewart
27978a859b ui: avoid panic when terminal window is shrunk
When using a tiling window manager, aerc terminal dimensions may be
greatly reduced after a new window has been created by :open. When the
ui attempts to render to formerly-valid coordinates, SetCell & Printf
may panic. Replace panic() with no-op in both functions to prevent
aerc from crashing after a window shrink.

Signed-off-by: Jason Stewart <support@eggplantsd.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-26 17:32:00 +02:00
Tim Culverhouse
4c3565653a textinput: prevent data race from debounce function
Protect access to fields in textinput. Concurrent access can happen in
the main event loop and the completion debounce function.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-26 17:32:00 +02:00
Tim Culverhouse
978768bff6 idler: fix data race for access to idleing and waiting
Protect access to fields idleing and waiting via a mutex.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-26 17:32:00 +02:00
Tim Culverhouse
9e54c921c8 checkmail: protect access to acct.checkingmail
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>
2022-09-26 17:32:00 +02:00
Tim Culverhouse
716ade8968 worker: lock access to callback maps
Worker callbacks are inherently set and called from different
goroutines. Protect access to all callback maps with a mutex.

Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-26 17:31:53 +02:00
Tim Culverhouse
c8c4b8c7cb dirlist: avoid race from accessing ui config in Select debounce
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-26 17:31:15 +02:00
Tim Culverhouse
c89c37e808 gitignore: ignore race.log.*
Running `make dev` creates race.log.* files. Ignore these by default.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-26 17:31:10 +02:00
Tim Culverhouse
c4a9f3f8a0 terminal: prevent draw loop when unfocused
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>
2022-09-26 17:31:05 +02:00
Tim Culverhouse
da10dae86e terminal: bump tcell-term version
Bump tcell-term version to latest commit. Intention is to release
tcell-term v0.2.0 just before aerc 0.13.0.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-25 11:54:29 +02:00
Tim Culverhouse
e7a51f5524 backends: send MessageInfoError on header fetching error
When an error is encountered fetching a header, the backends respond
with a type.Error worker message. On receipt of this message, the UI
deletes all pending headers. The headers are all requested again as they
remain on the screen, resulting in an infinite request loop - and an
infinite logging loop. The user only ever sees the spinner unless they
check the logs.

A previous commit intended to fix this, however it introduced a
regression where any message that was part of the fetch request would
also be marked as erroneous. This commit is reverted with commit
2aad2fea7d36 ("msgstore: revert 9fdc7acf5b48").

Send an erroneous message info message from the backend when an error is
encountered for a specific UID.

Fixes: 01f80721e2 ("msgstore: post MessageInfo on erroneous fetch")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-25 11:54:27 +02:00
Tim Culverhouse
a9af5635bc msgstore: revert 9fdc7acf5b "post messageInfo on erroneous fetch"
Commit 9fdc7acf5b ("cache: fetch flags from UI") introduced a
regression where all messages were marked as erroneous if a single one
in the fetch request had an error.

Reported-by: Jose Lombera <jose@lombera.dev>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-25 11:54:26 +02:00
Koni Marti
e5b0725824 charset: handle unknown charsets more user-friendly
Do not throw an error when the charset is unknown; the message entity
can still be read, but log the error instead.

Reported-by: falsifian
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-25 11:54:23 +02:00
Robin Jarry
41822a6123 config: add default-save-path in default aerc.conf
This setting has been around for ages but not in the default aerc.conf
file. Add it to make it more visible to new users.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-09-25 11:42:05 +02:00
Robin Jarry
24e30f7f1f config: remove default values for this-*-time-format
Having a default value is confusing because to disable the dynamic time
format, the users need to explicitly configure these settings to the
empty string.

Do not set default values for these settings when they are unset in the
configuration. Comment the default config file values to serve as
examples.

Fixes: aae29324fd ("config: fix default time format values")
Reported-by: Nicolai Dagestad <nicolai@dagestad.fr>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-09-25 11:42:05 +02:00
Tim Culverhouse
9fdc7acf5b cache: fetch flags from UI
When cached headers are fetched, an action is posted back to the Worker
to immediately fetch the flags for the message from the server (we can't
know the flags state, therefore it's not cached). When scrolling, a lag
occurs when loading cached headers because the n+1 message has to wait
for the flag request to return before the cached headers are retrieved.

Collect the message UIDs in the UI that need flags, and fetch them based
off a debounce timer in a single request. Post the action from the UI to
eliminate an (ugly) go routine in the worker.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 21:10:35 +02:00
Tim Culverhouse
a91009edf7 grid: protect calls to cell.Content
Many panics occur from calling Draw on a nil widget, stemming from the
grid ui element. Protect the calls to Draw from within grid to prevent
this method of panic.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 21:07:42 +02:00
Tim Culverhouse
a31606db0d grid: remove unused method Children
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>
2022-09-20 21:06:08 +02:00
Tim Culverhouse
aa01f0f6dc dirlist: don't invalidate on spinner.Invalidate
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>
2022-09-20 21:05:48 +02:00
Koni Marti
044519e1dc switch: update status line
Update status line when switching accounts in the composer.

Fixes: 371c1a ("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>
2022-09-20 21:05:15 +02:00
Robin Jarry
bb9ac43e13 switch: add -n and -p flags for relative switch
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>
2022-09-20 20:55:29 +02:00
Robin Jarry
fcd75ab529 mk: make it obvious that GOFLAGS change cause a rebuild
We had a few issues with that for downstream distros recently.

Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-09-20 11:37:58 +02:00
Moritz Poldrack
ddca71bcfd Revert "worker: prevent deadlock by flooding worker.Messages channel"
This reverts commit 7473571159.

The commit has introduced a regression that lead to the pager not being
filled with content, thereby making reading mails impossible.

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:37:42 +02:00
Robin Jarry
f59ca5af36 changelog: add missing entry
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:14:38 +02:00
Tim Culverhouse
01f80721e2 msgstore: post MessageInfo on erroneous fetch
When errors occur during a fetch header request, the requested headers
are deleted from pending and no information is given to the UI. Spinners
keep spinning, and ultimately as the view is refreshed, the headers are
fetched again. This can lead to infinite loops, and extremely long logs.

Update the store with a MessageInfo message when an error is received.
Have the UI display that the header couldn't be fetched in the message
list.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:03:36 +02:00
Tim Culverhouse
7473571159 worker: prevent deadlock by flooding worker.Messages channel
Send to worker.Messages in goroutine to prevent deadlocks: the UI can
fill the worker.Actions channel. The worker can generate more than one
Message per action, and if it generates enough to fill the
worker.Messages channel from a single message while the worker.Actions
channel is full, a deadlock occurs.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:03:36 +02:00
Tim Culverhouse
f4d6ade429 imap: prevent deadlock from posting actions to self
The IMAP worker has a few methods that post a new Action to itself. This
can create a deadlock when the worker.Actions channel is full: The
worker can't accept a new Action because it's trying to post an action.
This is most noticeable when cached headers are enabled and the message
list is scrolled fast.

Use a goroutine to post actions to the worker when posting from within
the worker.

Fixes: https://todo.sr.ht/~rjarry/aerc/45
Fixes: 7aa71d334b ("imap: add option to cache headers")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:03:36 +02:00
Robin Jarry
e808b96d63 binds: allow typing ? in subject header
Since commit 5c8a749cfa ("binds: display active keybinds in a dialog
box") the ? key is bound to `:help keys` in the global section which
applies to all binding contexts. Pressing ? while editing any email
headers in the compose window (when the editor is not selected) displays
the active bindings menu.

Add $noinherit=true in the [compose] context to allow typing any
character. Copy the bindings for next-tab and prev-tab so that users can
still change tabs while editing headers.

Cc: Akspecs <akspecs@gmail.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:03:28 +02:00
Koni Marti
d371c1ac8d commands: add switch-account command for composer
Switch accounts when in the composer mode. When switching accounts, the
From header, the crypto status and the address completer will be
updated.

Accounts can be switched with :switch-account <account-name>. The
completions for the switch-account command will list the available
accounts. If switch-account is run without arguments, the current
account name with the correct usage is displayed.

Fixes: https://todo.sr.ht/~rjarry/aerc/72
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-19 21:26:34 +02:00
Koni Marti
ee4f2ea49d composer: restructure to implement account switching
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>
2022-09-19 21:25:18 +02:00
Robin Jarry
b31bb1876b msgviewer: fix segfault when closing viewer
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>
2022-09-19 21:25:13 +02:00
Tim Culverhouse
cb84df09f6 terminal: don't invalidate on EventWidgetContent
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>
2022-09-19 21:25:11 +02:00
Bence Ferdinandy
74fd5d1119 statusline-format: add %p placeholder for current path
Allow showing the current working directory in the statusline via
[statusline] render-format=%p, which is useful if the user changes
directories often.

Signed-off-by: Bence Ferdinandy <bence@ferdinandy.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-19 21:25:10 +02:00
Tim Culverhouse
f414db7858 terminal: protect calls to terminal methods throughout aerc
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>
2022-09-19 21:25:09 +02:00
Tim Culverhouse
a44d1f6cc5 doc: document IMAP idle options
Add idle-debounce and idle-timeout to aerc-imap manpage.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-15 20:59:19 +02:00
Tim Culverhouse
599b9f6d46 terminal: improve mouse support
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>
2022-09-15 20:59:13 +02:00
Robin Jarry
77f69501d6 msgviewer: properly close embedded terminal
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>
2022-09-15 20:50:44 +02:00
Tim Culverhouse
c7df28d632 terminal: check for context before calling it's methods
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>
2022-09-15 20:50:38 +02:00
Tim Culverhouse
cf319129de term: add bracketed paste support
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>
2022-09-14 22:19:42 +02:00
Tim Culverhouse
518f3e962c term: replace go-libvterm with tcell-term
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>
2022-09-14 22:18:35 +02:00
Tim Culverhouse
17c4781911 ui: export context.viewport, screen.show, add SetCursorStyle
Export context.viewport for use in implementing tcell-term.

Bump tcell version to enable SetCursorStyle feature. Add this function
to the ui for future use with tcell-term.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-14 22:12:37 +02:00
Robin Jarry
ee7937d0dd ui: cleanup internals and api
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>
2022-09-14 22:11:33 +02:00
Robin Jarry
d93ad24f5f go mod tidy
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-09-14 20:52:10 +02:00
Moritz Poldrack
1418b283ab lint: update linter version
Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-14 20:52:04 +02:00
Moritz Poldrack
dcaabd5adf lint: warn about known security issues
Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-14 20:51:57 +02:00
Moritz Poldrack
ef99ec17d6 history: store command history in a file
Losing your progress in case of a crash, or when accidentally closing
aerc is annoying and costs time. This can be drastically reduced by
keeping a persistent history.

Write commands to XDG_CACHE_DIR/aerc/histfile when they are run and load
them when needed. If another instance of aerc is already writing the
file, fall back to the current model, where the history is kept in
memory.

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
2022-09-14 20:51:51 +02:00
Moritz Poldrack
9c11ab21c7 history: don't store duplicate entries
Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-14 20:51:41 +02:00