aerc/widgets/exline.go
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

118 lines
2.6 KiB
Go

package widgets
import (
"github.com/gdamore/tcell/v2"
"git.sr.ht/~rjarry/aerc/config"
"git.sr.ht/~rjarry/aerc/lib"
"git.sr.ht/~rjarry/aerc/lib/ui"
)
type ExLine struct {
ui.Invalidatable
commit func(cmd string)
finish func()
tabcomplete func(cmd string) ([]string, string)
cmdHistory lib.History
input *ui.TextInput
conf *config.AercConfig
}
func NewExLine(conf *config.AercConfig, cmd string, commit func(cmd string), finish func(),
tabcomplete func(cmd string) ([]string, string),
cmdHistory lib.History,
) *ExLine {
input := ui.NewTextInput("", &conf.Ui).Prompt(":").Set(cmd)
if conf.Ui.CompletionPopovers {
input.TabComplete(tabcomplete, conf.Ui.CompletionDelay)
}
exline := &ExLine{
commit: commit,
finish: finish,
tabcomplete: tabcomplete,
cmdHistory: cmdHistory,
input: input,
conf: conf,
}
input.OnInvalidate(func(d ui.Drawable) {
exline.Invalidate()
})
return exline
}
func (x *ExLine) TabComplete(tabComplete func(string) ([]string, string)) {
x.input.TabComplete(tabComplete, x.conf.Ui.CompletionDelay)
}
func NewPrompt(conf *config.AercConfig, prompt string, commit func(text string),
tabcomplete func(cmd string) ([]string, string),
) *ExLine {
input := ui.NewTextInput("", &conf.Ui).Prompt(prompt)
if conf.Ui.CompletionPopovers {
input.TabComplete(tabcomplete, conf.Ui.CompletionDelay)
}
exline := &ExLine{
commit: commit,
tabcomplete: tabcomplete,
cmdHistory: &nullHistory{input: input},
input: input,
}
input.OnInvalidate(func(d ui.Drawable) {
exline.Invalidate()
})
return exline
}
func (ex *ExLine) Invalidate() {
ex.DoInvalidate(ex)
}
func (ex *ExLine) Draw(ctx *ui.Context) {
ex.input.Draw(ctx)
}
func (ex *ExLine) Focus(focus bool) {
ex.input.Focus(focus)
}
func (ex *ExLine) Event(event tcell.Event) bool {
if event, ok := event.(*tcell.EventKey); ok {
switch event.Key() {
case tcell.KeyEnter, tcell.KeyCtrlJ:
cmd := ex.input.String()
ex.input.Focus(false)
ex.commit(cmd)
ex.finish()
case tcell.KeyUp:
ex.input.Set(ex.cmdHistory.Prev())
ex.Invalidate()
case tcell.KeyDown:
ex.input.Set(ex.cmdHistory.Next())
ex.Invalidate()
case tcell.KeyEsc, tcell.KeyCtrlC:
ex.input.Focus(false)
ex.cmdHistory.Reset()
ex.finish()
default:
return ex.input.Event(event)
}
}
return true
}
type nullHistory struct {
input *ui.TextInput
}
func (*nullHistory) Add(string) {}
func (h *nullHistory) Next() string {
return h.input.String()
}
func (h *nullHistory) Prev() string {
return h.input.String()
}
func (*nullHistory) Reset() {}