aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ui/textinput.go
Commit message (Collapse)AuthorAgeFilesLines
* ui: make textinput grapheme awareTim Culverhouse2024-07-021-20/+35
| | | | | | | | | | | | | | | | | The textinput widget operated on a slice of runes, and naively assumed a rune was a "character". When deleting or navigating the cursor through text which contains multi-codepoint characters (such as emoji), the cursor index could desync and cause panics. Use a slice of vaxis.Characters instead of runes to more accurately reflect the index state of the cursor with respect to characters. Fixes: https://todo.sr.ht/~rjarry/aerc/263 Reported-by: Bence Ferdinandy <bence@ferdinandy.com> Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Tested-by: Bence Ferdinandy <bence@ferdinandy.com> Reviewed-by: Koni Marti <koni.marti@gmail.com> 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>
* mouse: use vaxis mouse eventsTim Culverhouse2024-02-121-4/+3
| | | | | | | Replace all tcell.EventMouse events with vaxis mouse events 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-21/+25
| | | | | | | 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: remove screen and viewportsTim Culverhouse2024-02-121-2/+2
| | | | | | | | 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-2/+3
| | | | | | | | | | 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>
* complete: only display popover for more than one choiceRobin Jarry2023-11-221-64/+74
| | | | | | | | | | When there is only one completion choice available, accept the completion immediately upon a <Tab> key press. This is consistent with how most completion engines work (bash, vim, etc.). Reported-by: Johannes Thyssen Tishman <johannes@thyssentishman.com> Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Johannes Thyssen Tishman <johannes@thyssentishman.com>
* completion: hide quotes from choicesRobin Jarry2023-11-121-3/+10
| | | | | | | | | | | | When completion choices are surrounded by quotes to make sure that they will be interpreted as a single argument, hide them before presenting the choices to the user. It makes the UI cluttered and harder to read. The completion values remain identical, the quotes will be inserted when the user accepts one choice. Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Inwit <inwit@sindominio.net>
* complete: allow disabling automatic completionRobin Jarry2023-11-021-0/+4
| | | | | | | | | | | Allow setting complete-min-chars = manual to disable automatic completion. Changelog-added: Setting `complete-min-chars=manual` in `aerc.conf` now disables automatic completion, leaving only manually triggered completion. Signed-off-by: Robin Jarry <robin@jarry.cc> Reviewed-by: Tim Culverhouse <tim@timculverhouse.com>
* complete: allow setting the completion key bindingRobin Jarry2023-11-021-18/+12
| | | | | | | | | | | | | | | | | | | | | Until now, if less than complete-min-chars were entered or if completion-delay had not expired yet, the only way to force trigger completion was to press <tab>. In some cases, <tab> is already bound to another action (for example :next-field in the compose::editor context). This makes forcing the completion impossible. Allow defining a key to trigger manual completion via the new $complete special entry in binds.conf. Leave the default binding to <tab>. Set it to <C-o> in the [compose::editor] to avoid conflicting with the existing <tab> binding. Changelog-added: Customize key to trigger completion with `$complete` in `binds.conf`. Signed-off-by: Robin Jarry <robin@jarry.cc> Reviewed-by: Tim Culverhouse <tim@timculverhouse.com>
* textinput: fix deleteWord with an only whitespaceOskar Sharipov2023-07-281-1/+1
| | | | | | | | | | | Fix a panic in the textinput.deleteWord when text is a whitespace symbol. Add tests for textinput. Fixes: https://todo.sr.ht/~rjarry/aerc/183 Signed-off-by: Oskar Sharipov <oskargit@riseup.net> Acked-by: Robin Jarry <robin@jarry.cc>
* textinput: fix stemming with multi-byte charsKoni Marti2023-06-221-1/+1
| | | | | | | | | Fix a panic in the textinput when using multi-byte chars in the completions. Fixes: https://todo.sr.ht/~rjarry/aerc/180 Signed-off-by: Koni Marti <koni.marti@gmail.com> Tested-by: Bence Ferdinandy <bence@ferdinandy.com>
* ui: fix deadlocks in message channelRobin Jarry2023-05-201-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* textinput: align completion popoverKoni Marti2023-05-161-1/+10
| | | | | | | | Align the completion popover with the actual completion location on the textinput line. Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
* textinput: improve stemmingKoni Marti2023-05-161-3/+6
| | | | | | | | | | | | | | | | | | | | | | Fix cursor index after stemming and reset it to the position where the completion should occur. Only stem to add more information and not remove any user input. Stemming is activated on the textinput line when the user presses the Tab key. The idea of stemming is to adjust the textinput line to the common ground (="the stem") of the completions options. When the stemmed input line is set, however, the cursor will be moved to the end of the line if there is a text part on the right side of the cursor where the completion should occur. Another Tab press will activate the onStem function again, which then removes the right part of the text input leading to the loss of the user input. This can be prevented by moving the cursor to the place of the completion after stemming. Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
* textinput: fix crash when scrolling back in command historyRobin Jarry2023-01-021-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Pressing up while in command mode, calls TextInput.Set() with the previous command in the history. If the command exceeds the current terminal width, there is a scroll mechanism that puts the cursor at the end of the text (see ensureScroll()). However, the offset used to perform the draw is not the current scroll value but the "previous" one. When the one before last command required a longer scroll offset than the current command length, this causes a crash: Error: runtime error: slice bounds out of range [348:5] git.sr.ht/~rjarry/aerc/lib/ui.(*TextInput).Draw(0xc0017ce000, 0xc005460570) git.sr.ht/~rjarry/aerc/lib/ui/textinput.go:111 +0x525 git.sr.ht/~rjarry/aerc/widgets.(*ExLine).Draw(0x30?, 0xc01de13b08?) git.sr.ht/~rjarry/aerc/widgets/exline.go:76 +0x1d git.sr.ht/~rjarry/aerc/lib/ui.(*Stack).Draw(0xc0003f0ff0?, 0x0?) git.sr.ht/~rjarry/aerc/lib/ui/stack.go:30 +0x49 git.sr.ht/~rjarry/aerc/lib/ui.(*Grid).Draw(0xc00038c240, 0xc0003f0ff0) git.sr.ht/~rjarry/aerc/lib/ui/grid.go:126 +0x225 git.sr.ht/~rjarry/aerc/widgets.(*Aerc).Draw(0xc0003f4000, 0xc0003f0ff0) git.sr.ht/~rjarry/aerc/widgets/aerc.go:176 +0x1d2 git.sr.ht/~rjarry/aerc/lib/ui.(*UI).Render(0xc0003a0000) git.sr.ht/~rjarry/aerc/lib/ui/ui.go:110 +0x63 main.main() git.sr.ht/~rjarry/aerc/aerc.go:255 +0x9c5 There are actually two distinct issues here: 1) The scroll offset used for drawing must be the current one, not the one from the previous ensureScoll() call. 2) The scroll offset must be reset when changing the text with TextInput.Set(). Other methods that change the text actually call ensureScroll but they make incremental changes to the text, since Set completely overwrites everything, it makes more sense to set the scroll offset to 0. Reported-by: Adam Cooper <adam@theadamcooper.com> Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Tim Culverhouse <tim@timculverhouse.com>
* logging: rename package to logRobin Jarry2022-12-021-2/+2
| | | | | | | | | | Use the same name than the builtin "log" package. That way, we do not risk logging in the wrong place. Suggested-by: Tim Culverhouse <tim@timculverhouse.com> Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Bence Ferdinandy <bence@ferdinandy.com> Acked-by: Tim Culverhouse <tim@timculverhouse.com>
* ui: invalidate ui when queuing redrawTim Culverhouse2022-11-061-1/+0
| | | | | | | | | | | | | | | 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>
* auto-completion: add option to require a min number of charsRobin Jarry2022-11-061-2/+8
| | | | | | | | | | When doing address completion via commands that take a while to run, having the completion trigger even with a single character can be non-optimal. Add an option to allow requiring a minimum number of characters to actually run the completion command. Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Tim Culverhouse <tim@timculverhouse.com>
* invalidatable: cleanup dead codeTim Culverhouse2022-10-121-4/+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>
* aerc: use single event loopTim Culverhouse2022-10-071-0/+1
| | | | | | | | | 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>
* textinput: prevent data race from debounce functionTim Culverhouse2022-09-261-0/+6
| | | | | | | | 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>
* lint: homogenize operations and minor fixes (gocritic)Moritz Poldrack2022-08-041-11/+7
| | | | | | | | | | | | | | | | | | 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/+2
| | | | | | | Run `make fmt`. Signed-off-by: Moritz Poldrack <git@moritz.sh> Acked-by: Robin Jarry <robin@jarry.cc>
* autocompletion: fix regressionKoni Marti2022-08-011-2/+2
| | | | | | | | | | | | | | | | | | | | | Commit 27425c15c4b9 ("autocompletion: fix slice out of bounds access") introduced a regression in the autocompletion that messes up the order of last entered chars when autocompletion runs. The ranges for a slice a[low:high] are 0 <= low <= high <= len(a) [0] To reproduce with the ":cf" command: 1) enter ":c" 2) wait for autocompleteion 3) enter "f" 4) the prompt will now be ":fc" [0]: https://go.dev/ref/spec#Slice_expressions Fixes: 27425c15c4b9 ("autocompletion: fix slice out of bounds access") Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
* autocompletion: fix slice out of bounds accessMoritz Poldrack2022-07-311-0/+3
| | | | | Signed-off-by: Moritz Poldrack <git@moritz.sh> Acked-by: Robin Jarry <robin@jarry.cc>
* uiconfig: use pointer references to uiConfigTim Culverhouse2022-07-031-3/+3
| | | | | | | | This patch changes references to uiConfig in function signatures and structs to be pointers. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
* pgp: check encryption keys before sending messageTim Culverhouse2022-05-061-0/+14
| | | | | | | | | | | | | | | | Add check for public keys of all message recipients (to, cc, and bcc) before sending the message. Adds an OnFocusLost callback to header editors to facilitate a callback for checking keys whenever a new recipient is added (OnChange results in too many keyring checks). Once encryption is initially set, the callbacks are registered. If a public key is not available for any recipient, encryption is turned off. However, notably, the callbacks are still registered meaning as s soon as the user removes the recipients with missing keys, encryption is turned back on. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Tested-by: Koni Marti <koni.marti@gmail.com>
* completion: install panic handler in completion callbackRobin Jarry2022-03-251-0/+2
| | | | | | | | | This callback is actually invoked in a goroutine by time.AfterFunc. The panic handler must be explicitly installed. Link: https://github.com/golang/go/blob/go1.18/src/time/sleep.go#L160-L173 Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Moritz Poldrack <moritz@poldrack.dev>
* lib/ui/textinput: stop at /, ", and ' charsPranjal Kole2022-02-031-5/+11
| | | | This matches the default behaviour of Ctrl+W in vim.
* completions: add support for completing multiple addressesParasrah2022-01-071-5/+6
| | | | | | | as per the discussion https://lists.sr.ht/~sircmpwn/aerc/patches/15367 this handles completions in `completer/completer.go` by enabling the completer to return a `prefix` that will be prepended to the selected completion candidate.
* go.mod: change base git urlRobin Jarry2021-11-051-1/+1
| | | | | | | I'm not sure what are the implications but it seems required. Link: https://github.com/golang/go/issues/20883 Signed-off-by: Robin Jarry <robin@jarry.cc>
* lib/ui/textinput: Optimize ensureScrollAdnan Maolood2021-08-301-5/+5
|
* 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.
* Implement style configuration.Kalyan Sriram2020-08-061-12/+20
| | | | | | Introduce the ability to configure stylesets, allowing customization of aerc's look (color scheme, font weight, etc). Default styleset is installed to /path/to/aerc/stylesets/default.
* Revert "Implement style configuration."Reto Brunner2020-07-301-20/+12
| | | | This reverts commit 1ff687ca2b0821c2cacc1fa725abb3302d2af9da.
* Implement style configuration.Kalyan Sriram2020-07-301-12/+20
| | | | | | Introduce the ability to configure stylesets, allowing customization of aerc's look (color scheme, font weight, etc). Default styleset is installed to /path/to/aerc/stylesets/default.
* Revert "Add Style configuration"Drew DeVault2020-05-281-20/+12
| | | | This reverts commit 0f78f06610c0e8887aba2ae50e99b86477a384b3.
* Add Style configurationReto Brunner2020-05-271-12/+20
| | | | | | | | | | The following functionalities are added to configure aerc ui styles. - Read stylesets from file with very basic fnmatch wildcard matching - Add default styleset - Support different stylesets as part of UiConfig allowing contextual styles. - Move widgets/ui elements to use the stylesets. - Add configuration manual for the styleset
* Fix array out of bounds errorburrowing-owl2020-05-051-1/+1
|
* 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 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.
* Add MouseableJeffas2019-09-111-0/+14
| | | | | | | | | | | | | | | | | | | | | | 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].
* 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 text input cursor position with non-ASCII textTuomas Siipola2019-07-171-3/+3
| | | | Fixes #171
* 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.
* ensureScroll on text input framesDrew DeVault2019-05-251-0/+2
|