summary refs log tree commit diff stats
path: root/lib/ui
Commit message (Collapse)AuthorAgeFilesLines
* fix: Close unused MessageView when swapping viewRay Ganardi2020-04-201-0/+5
| | | | | | | Closes https://todo.sr.ht/~sircmpwn/aerc2/379 The old `MessageView` was not closed when replacing the tab content, which causes a memory leak.
* Add pinned tabsJeffas2020-03-091-5/+62
| | | | | | This adds the commands pin-tab and unpin-tab. Once pinned a tab lives on the left of the tabstrip and has a configurable marker, defaulting to ` before its name.
* Initial support for PGP decryption & signaturesDrew DeVault2020-03-032-0/+8
|
* Add move-tab commandJeffas2020-03-031-0/+41
|
* compose: don't call ti.tabcomplete when it is nilTimmy Douglas2020-01-091-0/+4
|
* Don't select completions until tab has been pressedBen Burwell2020-01-051-6/+8
| | | | | | | | | | | | | | | Before, pressing <Enter> when completions were visible would execute the selected completion. As soon as completions were provided, the first item would be selected. This could cause issues e.g. when changing folders: :cf <Enter> Previously, this would have selected the first folder in the list. Now, since <Tab>, <C-n>, etc have not been pressed to select the first completion, the command above simply executes `:cf `. To accomplish this, a "no-op completion" has been added at index -1.
* Show textinput completions in popoversBen Burwell2019-12-211-50/+223
| | | | | | Rather than showing completions inline in the text input, show them in a popover which can be scrolled by repeatedly pressing the tab key. The selected completion can be executed by pressing enter.
* Add popoversBen Burwell2019-12-213-9/+102
| | | | | | | | | | | | 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.
* Add UI options to save/pipe messages with unsupported mimetypesGreg Anders2019-11-171-1/+2
| | | | | | | | | | | | | | | Adds a message indicating the user's ability to :save or :pipe a message with an unsupported mimetype and also adds a selector widget (similar to the tutorial). The selector widget was previously defined in the account wizard module, so this commit breaks it out into its own module to allow for re-use. Further, modify the BeginExLine() function to take an argument that pre-populates the command line, allowing functions to initiate an ex command without executing it. Closes #95.
* Fix tab refocus on removeJeffas2019-10-141-8/+14
| | | | | | | | Previously removing a tab would always pop from the history of tabs. This checks to see if the closing tab is the one selected, if it is then we use the history, otherwise we only need to change the selected tab if it was after (to the right of) the closing tab, in which case we just decrement the selected index.
* Fix pushing invalid tabs to historyJeffas2019-10-141-1/+4
| | | | A tab can now only be pushed onto the history if it is a selectable tab.
* Focus new tab after removeJeffas2019-09-181-0/+4
| | | | | After removing a tab we should focus the newly selected tab if it is Interactive. This ensures things like the terminal get drawn properly.
* Add MouseableJeffas2019-09-116-24/+164
| | | | | | | | | | | | | | | | | | | | | | This adds the Mouseable interface. When this is implemented for a component that item can accept and process mouseevents. At the top level when a mouse event is received it is passed to the grid's handler and then it trickles down until it reaches a component that can actually handle it, such as the tablist, dirlist or msglist. A mouse event is passed so that components can handle other things such as scrolling with the mousewheel. The components themselves then perform the necessary actions. Clicking emails in the messagelist opens them in a new tab. Textinputs can be clicked to position the cursor inside them. Mouseevents are not forwarded to the terminal at the moment. Elements which do not handle mouse events are not required to implement the Mouseable interface.
* Add delete forward <C-k> and backward <C-u>Christopher Vittal2019-08-121-0/+29
| | | | | | | | | | Choose the readline defaults for the behavior of these two functions/keybindings. Depending on the program, either of these can delete the whole line. Note that by default in [compose], <C-k> is bound to :prev-field<Enter>. Leave it up to the user whether or not they want to rebind the key in [compose].
* 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 arrive 0.2.0Ben Burwell2019-07-292-1/+11
| | | | | | | | 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.
* Fix tabstrip over-drawing when not enough spaceJeffas2019-07-261-1/+8
| | | | | | | | Tabstrip didn't take into account the width of the context. Now, it just shows as many tabs as can fit and truncates the last one if necessary. In future it probably would be best to ensure that the selected tab is rendered on the screen.
* Add tab completion to textinputsJeffas2019-07-261-10/+74
| | | | | | | | | | | | | This adds tab completion to textinput components. They can be configured with a completion function. This function is called when the user presses <tab>. The first completion is initially shown to the user inserted into the text. Repeated presses of <tab> or <backtab> cycle through the completions list. The completions list is invalidated when any other non-tab-like key is pressed. Also changed is some logic for current completion generation so that all available commands are returned when <tab> is pressed with no current text and similarly for arguments of commands.
* Fix invalid tab state when deselecting removed tabDrew DeVault2019-07-261-1/+1
|
* Fix :close on terminal panicJeffas2019-07-251-0/+5
| | | | | | | | Executing :close on a terminal would panic due to it already having been removed. This is also related to the fact that removing a tab doesn't check for whether it actually found a tab to remove or not.
* Fix grid creating too large subcontextsJeffas2019-07-251-0/+9
| | | | | | | | The grid was not checking there was enough space for the cells so would just attempt to create subcontexts that don't actually fit. This attempts to use the remaining space and then if there is no space then it just skips drawing this cell.
* Fix panic when tabs.popHistory is nonexistentDrew DeVault2019-07-251-1/+1
|
* Add change tab commandJeffas2019-07-231-5/+20
| | | | | | | | | | This command allows the user to change tab by giving the tab name. This can be tab completed too. The previous tab is stored in the tabs module so that when a new tab is created it is still possible to go to the previous one. Normal invocation is :ct folder Previous tab is :ct -
* Display user specified headers in viewer if presentDaniel Bridges2019-07-171-0/+14
|
* Fix grid widths when using weighted widthsJeffas2019-07-171-3/+14
| | | | | | | | | | If the column weights do not collectively divide the extent of the grid layout then some width was not used and so would not be redrawn, resulting in previous drawings showing through. This fixes this by checking if there is any remainingExact width and if there is it is assigned to the weighted columns by their proportion from left to right.
* 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.
* Fix text input cursor position with non-ASCII textTuomas Siipola2019-07-171-3/+3
| | | | Fixes #171
* Add clickable tabsJeffas2019-07-113-0/+36
| | | | | | | | | | | 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.
* Implement basic tab completion supportGregory Mullen2019-06-291-0/+8
| | | | | Tab completion currently only works on commands. Contextual completion will be added in the future.
* lib/ui/tab: Add Replace methodKevin Kuehler2019-06-111-0/+16
| | | | | | Also expose a light wrapper method in aerc.go for tab replacement Signed-off-by: Kevin Kuehler <kkuehler@brave.com>
* Fix #116 0.1.0Drew DeVault2019-06-031-1/+1
|
* Add Tabs historyReto Brunner2019-06-021-4/+34
| | | | Fixes #77: When closing a tab, bring you back to the one you last had focused
* ensureScroll on text input framesDrew DeVault2019-05-251-0/+2
|
* Implement scrolling in text inputDrew DeVault2019-05-251-3/+31
|
* Show account wizard if no accounts configuredDrew DeVault2019-05-221-1/+1
|
* New account wizard, part oneDrew DeVault2019-05-212-10/+23
|
* 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-192-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | 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
|
* Let caller pass in custom headers to composeDrew DeVault2019-05-161-0/+4
|
* Update tab name as subject changesDrew DeVault2019-05-142-1/+18
| | | | Also moves truncation to the tab widget
* Spec out review message screenDrew DeVault2019-05-131-3/+3
|
* Implement :{next,prev}-field in compose viewDrew DeVault2019-05-121-3/+3
|
* Add initial compose widgetDrew DeVault2019-05-121-2/+3
|
* Refactor ctx stashing out of exlineDrew DeVault2019-05-111-0/+2
|
* Split ex line text handling into dedicated widgetDrew DeVault2019-05-111-0/+136
|
* 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
* lib/ui: fix Grid race conditionSimon Ser2019-05-051-1/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This was is more complicated than others. The cells list is accessed by multiple goroutines: - Some change the Grid's contents via AddChild/RemoveChild - Some call Draw - Some invalidate the grid via Invalidate Invalidate calls are tricky to handle because they will also invalidate all child cells. This will inturn trigger the cellInvalidated callback, which needs to read the list of cells. For this reason, we use a sync.RWLock which allows multiple concurrent reads. Below is the race fixed by this commit. Read at 0x00c0000bc3d0 by goroutine 7: git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated() /home/simon/src/aerc2/lib/ui/grid.go:181 +0x45 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated-fm() /home/simon/src/aerc2/lib/ui/grid.go:179 +0x55 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate() /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Bordered).contentInvalidated-fm() /home/simon/src/aerc2/lib/ui/borders.go:39 +0x56 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate() /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85 git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList.func1() /home/simon/src/aerc2/widgets/dirlist.go:81 +0x55 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate() /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85 git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1() /home/simon/src/aerc2/widgets/spinner.go:88 +0x82 Previous write at 0x00c0000bc3d0 by main goroutine: [failed to restore the stack] Goroutine 7 (running) created at: git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start() /home/simon/src/aerc2/widgets/spinner.go:46 +0x98 git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList() /home/simon/src/aerc2/widgets/dirlist.go:37 +0x28b git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView() /home/simon/src/aerc2/widgets/account.go:49 +0x5ca git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc() /home/simon/src/aerc2/widgets/aerc.go:60 +0x807 main.main() /home/simon/src/aerc2/aerc.go:65 +0x33e
* lib/ui: fix GridCell.invalid raceSimon Ser2019-04-291-5/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is read/written from different goroutines. Write at 0x00c00009c6f0 by goroutine 7: git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated() /home/simon/src/aerc2/lib/ui/grid.go:189 +0x122 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated-fm() /home/simon/src/aerc2/lib/ui/grid.go:178 +0x55 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate() /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Bordered).contentInvalidated-fm() /home/simon/src/aerc2/lib/ui/borders.go:39 +0x56 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate() /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85 git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList.func1() /home/simon/src/aerc2/widgets/dirlist.go:81 +0x55 git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate() /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85 git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1() /home/simon/src/aerc2/widgets/spinner.go:88 +0x82 Previous write at 0x00c00009c6f0 by main goroutine: [failed to restore the stack] Goroutine 7 (running) created at: git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start() /home/simon/src/aerc2/widgets/spinner.go:46 +0x98 git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList() /home/simon/src/aerc2/widgets/dirlist.go:37 +0x28b git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView() /home/simon/src/aerc2/widgets/account.go:49 +0x5ca git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc() /home/simon/src/aerc2/widgets/aerc.go:60 +0x807 main.main() /home/simon/src/aerc2/aerc.go:65 +0x33e
* lib/ui: introduce InvalidatableSimon Ser2019-04-274-32/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Many Drawable implementations have their own Invalidate and OnInvalidate functions, with an unexported onInvalidate field. However OnInvalidate and Invalidate are usually not called in the same goroutine. This results in a race on this field, e.g.: Read at 0x00c000094748 by goroutine 7: git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList.func1() /home/simon/src/aerc2/widgets/dirlist.go:85 +0x56 git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1() /home/simon/src/aerc2/widgets/spinner.go:93 +0x1bb Previous write at 0x00c000094748 by main goroutine: [failed to restore the stack] Goroutine 7 (running) created at: git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start() /home/simon/src/aerc2/widgets/spinner.go:46 +0x8f git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList() /home/simon/src/aerc2/widgets/dirlist.go:37 +0x286 git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView() /home/simon/src/aerc2/widgets/account.go:50 +0x5ca git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc() /home/simon/src/aerc2/widgets/aerc.go:60 +0x800 main.main() /home/simon/src/aerc2/aerc.go:65 +0x33e To fix this, introduce a new type, Invalidatable, which protects the field. Unfortunately the Drawable must be passed to the callback function in Invalidate, so we still need to re-implement this in each Invalidatable user.