aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ui/ui.go
Commit message (Collapse)AuthorAgeFilesLines
* aerc: support terminal-based pinentry programsKoni Marti2024-10-121-0/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Support terminal-based pinentry programs. Suspend vaxis before running the command that can trigger a pinentry call. Provide the proper tty in the GPG_TTY environment variable (and set a TERM variable if not provided; this is necessary for pinentry-curses). Finally, resume vaxis. To enable terminal-based pinentry support, you have to set [general] use-terminal-pinentry = true in your aerc.conf. Any GUI-based pinentry programs will work the same as before if this option is not set to true. To test pinentry-tty, add the following to your ~/.gnupg/gpg-agent.conf: pinentry-program /usr/bin/pinentry-tty and kill all running gpg-agents: $ killall gpg-agent Fixes: https://todo.sr.ht/~rjarry/aerc/202 Changelog-fixed: Terminal-based pinentry programs (e.g. `pinentry-curses`) now work properly. Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
* ui: add :redraw commandTim Culverhouse2024-08-031-1/+13
| | | | | | | | | | | Add a :redraw command to force a repaint of the entire screen. Changelog-added: New `:redraw` command to force a repaint of the screen. Requested-by: Remko Tronçon <r@mko.re> Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Tested-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
* vaxis: fix panic trace print on stderrRobin Jarry2024-04-131-0/+1
| | | | | | | | | | | | | | | | | | By default, vaxis tries to open stderr, stdout and stdin in that order and uses the first one as its TTY file descriptor. Upon exit, vaxis.Close() closes that file descriptor. When aerc panics, our panic handler calls UICleanup() which is an alias for vaxis.Close(). This effectively makes os.Stderr unusable and all error messages are written to a closed file descriptor. This also break the regular go runtime panic() handler which prints on stderr as well. Use an explicit /dev/tty path instead of stderr to keep it open. Fixes: 6eff242090dc ("ui: so long tcell") Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Bence Ferdinandy <bence@ferdinandy.com> Reviewed-by: Tim Culverhouse <tim@timculverhouse.com>
* ui: update vaxis and only use disambiguate csi-u flagTim Culverhouse2024-02-261-0/+1
| | | | | | | | | | | | | | | | | | Update vaxis to 0.8.2, which adds the ability to specify any CSI-u flag combination. Explicitly only use the disambiguate flag. This enables aerc to have additional keybinds not previously possible (C-i, C-m) while preventing some internal logic bugs relating to single-modifier key presses. While these events can be useful, they are not needed in aerc and aerc currently would need several workarounds to properly handle them so let's just not request them in the first place. Fixes a bug with encoding shift+space in the presence of CSI-u in the terminal widget Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Tested-by: Inwit <inwit@sindominio.net> Tested-by: Jason Cox <dev@jasoncarloscox.com> Acked-by: Robin Jarry <robin@jarry.cc>
* ui: enable CSIu key encodingTim Culverhouse2024-02-221-2/+8
| | | | | | | | | | | | | | Enable CSIu key encoding protocol when support is detected. This will enable keybinds which traditionally have been unavailable due to conflicting with other keys (C-i, C-m, C-[, etc). Remove numlock and capslock from all keypresses to prevent interfering with key matching. Changelog-added: Virtually any key binding can now be configured in `binds.conf`, including Shift+Alt+Control modifier combinations. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* revert: "ui: enable kitty keyboard protocol"Robin Jarry2024-02-191-1/+2
| | | | | | | | | | | | | | This reverts commit d73cf33c2c6c3e564ce8aff04acc329a06eafc54. This breaks virtually all key bindings on foot. Almost zero ctrl- bindings work, and even in some cases, single key binds, like n don't register anymore. It looked harmless, but I should probably have tested before applying this. Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Tim Culverhouse <tim@timculverhouse.com>
* ui: enable kitty keyboard protocolTim Culverhouse2024-02-191-2/+1
| | | | | | | | | | | | Enable kitty keyboard protocol when support is detected. This will enable keybinds which traditionally have been unavailable due to conflicting with other keys (C-i, C-m, C-[, etc). Reported-by: Jonathan Dowland <jon+aerc-discuss@dow.land> Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Tested-by: Jonathan Dowland <jon@dow.land> Acked-by: Robin Jarry <robin@jarry.cc>
* log: move package to libRobin Jarry2024-02-141-1/+1
| | | | | | | This has nothing to do at the root of the source tree. Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Bence Ferdinandy <bence@ferdinandy.com>
* aerc: set title using vaxisTim Culverhouse2024-02-121-0/+1
| | | | | | | Set the window title using Vaxis at UI initialization. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* terminal: replace tcell-term with vaxis terminalTim Culverhouse2024-02-121-0/+1
| | | | | | | | Replace tcell terminal with the vaxis terminal. The vaxis terminal is a port of tcell term. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* aerc: replace tcell keys with vaxis keysTim Culverhouse2024-02-121-2/+0
| | | | | | | Replace all instances of tcell key usage with vaxis keys Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* ui: initialize vaxis directly, drop tcell.Screen initializationTim Culverhouse2024-02-121-27/+18
| | | | | | | | Use Vaxis library directly to initialize the UI, dropping the need for a tcell Screen implementation Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* ui: remove screen and viewportsTim Culverhouse2024-02-121-23/+26
| | | | | | | | Remove references to tcell.Screen or views.Viewports. Convert Contexts and the core UI struct to use Vaxis objects only. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* aerc: change event interfaces to vaxis eventsTim Culverhouse2024-02-121-1/+1
| | | | | | | | | | Modify the function signature of Event and MouseEvent interfaces to accept vaxis events. Note that because a vaxis event is an empty interface, the implementations are not affected and the events are delivered as they were before Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* msgviewer: implement inline image viewingTim Culverhouse2024-02-121-0/+1
| | | | | | | | | | | | | | | | | Implement inline image viewing for jpeg, png, bmp, tiff, and webp formats. When a user has no configured image filter and the image is supported and the terminal has either sixel or kitty image protocol support, the image will be displayed in the message viewer. Always clear the screen before each draw. This call is necessary in vaxis to allow for images to be cleared properly between renders. There is no performance impact: the call only resets each cell to a blank cell, and aerc will redraw each one already. Changelog-added: Inline image previews when no filter is defined for `image/*` and the terminal supports it. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* ui: so long tcellTim Culverhouse2024-02-121-1/+11
| | | | | | | | | | | | | Replace tcell with vaxis. Vaxis provides several new features (none of which are included in this commit). All behavior should be exactly the same as previous, with one exception: Vaxis does not have an internal terminfo library. Some terminals will now have RGB that didn't before, as well as any other feature that was falling back to some unknown state. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* commands: add :suspendNojus Gudinavičius2023-10-241-0/+33
| | | | | | | | | Add :suspend to suspend the aerc process, returning to shell. Include documentation and default Ctrl-z keybinding for it. Changelog-added: New `:suspend` command bound to `<C-z>` by default. Signed-off-by: Nojus Gudinavičius <nojus.gudinavicius@gmail.com> Signed-off-by: Robin Jarry <robin@jarry.cc>
* ui: export global functionsRobin Jarry2023-10-111-43/+28
| | | | | | | | | | | | | There is no need for an UI object. The Aerc.ui field is unused. And there is a single instance of it anyway. Move the object's public fields as global variables and change methods to public functions. This makes the code cleaner and removes boilerplate. Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Moritz Poldrack <moritz@poldrack.dev>
* ui: fix deadlocks in message channelRobin Jarry2023-05-201-38/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | There are several ways the ui message channel can fill up leading to deadlocks. 1) Invalidate() changes the value of uiState to DIRTY. The following call sequence: QueueRedraw() Invalidate() QueueRedraw() Leads to multiple nil messages being queued in the message channel whereas one could assume that the second QueueRedraw() would do nothing. This is caused by the tri-state nature of uiState. 2) We use the same channel to convey state change, keyboard events and redraw requests. Since a keyboard event almost always triggers a redraw, we end up trying to append a redraw message in the same goroutine that reads from the channel. This triggers a deadlock when there are more than 50 pending messages. Solve the issue by using multiple channels, one per type of message that needs to be sent to the main ui thread. Remove QueueRedraw() and merge its functionality in Invalidate(). Only use a DIRTY/CLEAN state to determine if something needs to be queued in the redraw channel. Use a channel for quitting instead of an atomic. Restructure some code functions to have a cleaner API. Use a for loop in the main thread and select from all channels. Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Koni Marti <koni.marti@gmail.com> Tested-by: Maarten van Gompel <proycon@anaproy.nl>
* ui: avoid races with queue redrawRobin Jarry2023-04-271-15/+11
| | | | | | | | | | | | | | | | | | When calling ui.QueueRedraw() and a redraw is currently in progress, the redraw int value still holds REDRAW_PENDING since it is updated once the redraw is finished. This can lead to incomplete screen redraws on the embedded terminal. Even changing the redraw value before starting to redraw is exposed to races. Use a single atomic int to represent the state of the UI so that there cannot be any confusion. Rename the constants to make them less confusing. Fixes: b148b94cfe1f ("ui: avoid duplicate queued redraws") Reported-by: Jason Cox <dev@jasoncarloscox.com> Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Jason Cox <dev@jasoncarloscox.com>
* ui: avoid duplicate queued redrawsRobin Jarry2023-04-261-1/+8
| | | | | | | | | No need to queue multiple nil messages to force multiple redraws. Only one is required. When the screen is redrawn, clear the queued redraw flag. Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Tim Culverhouse <tim@timculverhouse.com>
* lint: add missing panic handlers in goroutinesRobin Jarry2023-01-061-0/+2
| | | | | | | | These issues were all reported by the new custom analyzer introduced in previous commit. Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Bence Ferdinandy <bence@ferdinandy.com>
* ui: invalidate ui when queuing redrawTim Culverhouse2022-11-061-2/+3
| | | | | | | | | | | | | | | The QueueRedraw function should always be preceeded by a call to ui.Invalidate in order to make a redraw a occur. In one instance, this was not done and it was possible for the UI to not redraw itself (when a terminal closes, a UI redraw request is made but it is possible for the UI to not be invalidated as a result of the close). Move the call to Invalidate into the QueueRedraw function to ensure that every QueueRedraw call will redraw the screen. Fixes: https://todo.sr.ht/~rjarry/aerc/98 Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* aercmsg: add AercFuncMsg and QueueFuncTim Culverhouse2022-10-181-0/+10
| | | | | | | | | | Introduce AercFuncMsg and QueueFunc. These are used in combination to queue a function to be run in the main goroutine. This can be used to prevent data races in delayed function calls (ie from debounce functions). Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* invalidatable: cleanup dead codeTim Culverhouse2022-10-121-1/+1
| | | | | | | | 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>
* invalidatable: always mark ui as dirty OnInvalidateTim Culverhouse2022-10-071-7/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | The Invalidatable struct is designed so that a widget can have a callback function ran when it is Invalidated. This is used to cascade up the widget tree, marking things as Invalid along the way so that only Invalid widgets are drawn. However, this is only implemented at the grid cell level for checks if the cell is invalidated -- and the grid cells are never set back to a "valid" state. The effect of this is that no matter what is invalidated, the entire UI gets drawn again. The calling through the Invalidate callbacks creates *several* race conditions, as Invalidate is called from several different goroutines, and many widgets call invalidate on their parent or children. Tcell has optimizations to only rerender screen cells that have changed their rune and style. The only performance penalty by redrawing the entire screen for aerc is the operations *within the aerc draw methods*. Most of these are not expensive and have relatively no impact on performance. Skip all of the OnInvalidates, and directly invalidate the UI when DoInvalidate is called by a widget. This reduces data races, and simplifies the widget redraw logic signficantly. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* render: clean up render codeTim Culverhouse2022-10-071-11/+1
| | | | | | | | | | | | The render method sets everything as invalid if there was a popover. This is no longer necessary, as everything is redrawn anyways. Remove the check and extra atomic set of dirty and invalidate. Remove unused return value Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* aerc: use single event loopTim Culverhouse2022-10-071-16/+18
| | | | | | | | | 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>
* events: introduce AercMsg and QueueRedrawTim Culverhouse2022-10-071-0/+8
| | | | | | | | | | Add AercMsg as a main interface for internal communication in aerc in preparation for a main event loop. Add a QueueRedraw function to to trigger a redraw. This will be needed for widgets which should be drawn after some delay (completions, terminal, for example) Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* term: add bracketed paste supportTim Culverhouse2022-09-141-0/+1
| | | | | | | | 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>
* ui: cleanup internals and apiRobin Jarry2022-09-141-15/+7
| | | | | | | | | | | | | | | | 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>
* ui: process tcell events in a separate go routine from renderingTim Culverhouse2022-09-131-17/+16
| | | | | | | | | | | | | The UI runs off a 16 ms ticker. If no render is required, and no event is seen, aerc waits 16 ms before checking for new events or render requests. This severely limits handling of events from tcell, and is particularly noticeable on pasting of large quantities of text. Process tcell events in a separate go routine from the render loop. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Moritz Poldrack <moritz@poldrack.dev> Acked-by: Robin Jarry <robin@jarry.cc>
* lint: homogenize operations and minor fixes (gocritic)Moritz Poldrack2022-08-041-2/+1
| | | | | | | | | | | | | | | | | | 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>
* lint: apply new formatting rulesMoritz Poldrack2022-08-011-1/+0
| | | | | | | Run `make fmt`. Signed-off-by: Moritz Poldrack <git@moritz.sh> Acked-by: Robin Jarry <robin@jarry.cc>
* logging: added a log on panicMoritz Poldrack2022-03-231-0/+3
| | | | | | | | | | | | | Since panics still regularly "destroy" the terminal, it is hard to get a stack trace for panics you do not anticipate. This commit adds a panic handler that automatically creates a logfile inside the current working directory. It has to be added to every goroutine that is started and will repair the terminal on a panic. Signed-off-by: Moritz Poldrack <git@moritz.sh> Acked-by: Robin Jarry <robin@jarry.cc>
* update tcell to v2 and enable TrueColor supporty0ast2020-12-181-1/+1
| | | | | | | | | Also update to the tcell v2 PaletteColor api, which should keep the chosen theme of the user intact. Note, that if $TRUECOLOR is defined and a truecolor given, aerc will now stop clipping the value to one of the theme colors. Generally this is desired behaviour though.
* libui: don't require beeper for main contentDrew DeVault2020-05-051-2/+4
|
* Initial support for PGP decryption & signaturesDrew DeVault2020-03-031-0/+4
|
* Add popoversBen Burwell2019-12-211-3/+23
| | | | | | | | | | | | A popover is a special UI element which can be layered over the rest of the UI (i.e. it is painted last) and can fall anywhere on the screen, not just with the bounds of its parent's viewport/context. With these special abilities comes the restriction that only one popover may be visible on screen at once. Popovers are requested from the UI context passed to Draw calls and specify the anchor point and the desired dimensions. The popover is then fit to the available space and placed relative to the anchor point.
* Remove aerc specific code from the uiNicolai Dagestad2019-08-031-7/+5
| | | | | Separatiing the ui code from aerc makes it usable as a library in other projects.
* Ring bell when new messages arrive0.2.0Ben Burwell2019-07-291-1/+2
| | | | | | | | Add a "new-message-bell" option to the UI section of aerc.conf. A new hook into the message store allows the msglist widget to detect new messages being added to the displayed list. When new messages are delivered, and the new-message-bell option is enabled (as it is by default), the terminal will beep.
* Add MouseEnabled config settingJeffas2019-07-171-1/+3
| | | | | This patch adds the ability to control whether aerc captures mouseevents or not. By default it will be set to not capture events.
* Add clickable tabsJeffas2019-07-111-0/+1
| | | | | | | | | | | This introduces a new interface `Clickable`. I'd imagine this would be implemented for most widgets eventually and would allow for programs run in the terminal to also have their mouse events forwarded to them. For the tabs it was relatively simple to check that the position of the click is within the boxes for the tabs. For other components I'd imagine that some state representing their currently drawn bounding box would be useful.
* lib/ui/ui: use atomic instead of channelSimon Ser2019-05-191-26/+21
| | | | | | | | | This makes it so an atomic `invalid` value is used instead of an unbuffered channel. When many invalidations kick in, a lot of values were sent to the channel. (Since OnInvalidate's callback can be run in any goroutine, we need to be careful about races here.)
* Update internal state and draw from the same goroutineSimon Ser2019-05-191-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | This commit introduces a new Aerc.Tick function that should be called to refresh the internal state. This in turn makes each AccountView process worker events. The UI goroutine repeatedly refreshes the internal state before drawing a new frame. The reason for this is that many worker messages may need to be processed for a single frame, and drawing the UI is far slower than refreshing the internal state. This has been confirmed in my testing (calling Aerc.Tick only once per frame results in a slower display). Many synchronization code has been removed. We can now write widgets without having to care so much about races. The remaining sync users are: - widgets/spinner: the spinner value is updated from inside an internal goroutine - lib/ui/invalidatable: Invalidate may be called from any goroutine - lib/ui/grid: same - lib/ui/ui: an internal goroutine needs read access to UI.exit - worker/types/worker: Worker.callbacks is used for both worker and UI callbacks The exact goroutine requirements for Drawable have been documented.
* s/aerc2/aerc/gDrew DeVault2019-05-171-1/+1
|
* lib/ui: fix UI.Exit race conditionSimon Ser2019-05-051-2/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | UI.Exit can be accessed from goroutines drawing, goroutines executing commands and goroutines waiting for events. Write at 0x00c0002b2040 by main goroutine: main.main.func1() /home/simon/src/aerc2/aerc.go:76 +0x33d git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).BeginExCommand.func1() /home/simon/src/aerc2/widgets/aerc.go:245 +0x89 git.sr.ht/~sircmpwn/aerc2/widgets.(*ExLine).Event() /home/simon/src/aerc2/widgets/exline.go:131 +0x442 git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).Event() /home/simon/src/aerc2/widgets/aerc.go:116 +0x83c git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).simulate() /home/simon/src/aerc2/widgets/aerc.go:109 +0x12a git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).Event() /home/simon/src/aerc2/widgets/aerc.go:142 +0x722 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*UI).Tick() /home/simon/src/aerc2/lib/ui/ui.go:75 +0x33f main.main() /home/simon/src/aerc2/aerc.go:94 +0x497 Previous read at 0x00c0002b2040 by goroutine 19: git.sr.ht/~sircmpwn/aerc2/lib/ui.Initialize.func1() /home/simon/src/aerc2/lib/ui/ui.go:45 +0x97 Goroutine 19 (running) created at: git.sr.ht/~sircmpwn/aerc2/lib/ui.Initialize() /home/simon/src/aerc2/lib/ui/ui.go:44 +0x372 main.main() /home/simon/src/aerc2/aerc.go:87 +0x3a9
* Add basic terminal widgetDrew DeVault2019-03-171-0/+1
|
* Add :quit commandDrew DeVault2019-03-151-5/+0
|
* Make repeated invalidations more efficientDrew DeVault2019-01-141-0/+10
|