mirror of
https://git.sr.ht/~rjarry/aerc
synced 2025-02-22 23:23:57 +01:00

Make the Completer interface accept a context.Context. Provide a cancellation feature on text input tab completion to cancel an inflight completion command. This is particularly useful for address book completion if the user has specified a network-accessing command, eg carddav-query. The command is started according to the completion delay, but is cancellable if another request comes in. We also check for cancellation after the request is complete to ensure we only show valid completion results. Changelog-changed: Tab completions for text fields are run asynchronously. In-flight requests are cancelled when new input arrives. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
125 lines
2.8 KiB
Go
125 lines
2.8 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
|
|
"git.sr.ht/~rjarry/aerc/config"
|
|
"git.sr.ht/~rjarry/aerc/lib"
|
|
"git.sr.ht/~rjarry/aerc/lib/ui"
|
|
"git.sr.ht/~rjarry/go-opt/v2"
|
|
"git.sr.ht/~rockorager/vaxis"
|
|
)
|
|
|
|
type ExLine struct {
|
|
commit func(cmd string)
|
|
finish func()
|
|
tabcomplete func(ctx context.Context, cmd string) ([]opt.Completion, string)
|
|
cmdHistory lib.History
|
|
input *ui.TextInput
|
|
}
|
|
|
|
func NewExLine(cmd string, commit func(cmd string), finish func(),
|
|
tabcomplete func(ctx context.Context, cmd string) ([]opt.Completion, string),
|
|
cmdHistory lib.History,
|
|
) *ExLine {
|
|
input := ui.NewTextInput("", config.Ui).Prompt(":").Set(cmd)
|
|
if config.Ui.CompletionPopovers {
|
|
input.TabComplete(
|
|
tabcomplete,
|
|
config.Ui.CompletionDelay,
|
|
config.Ui.CompletionMinChars,
|
|
&config.Binds.Global.CompleteKey,
|
|
)
|
|
}
|
|
exline := &ExLine{
|
|
commit: commit,
|
|
finish: finish,
|
|
tabcomplete: tabcomplete,
|
|
cmdHistory: cmdHistory,
|
|
input: input,
|
|
}
|
|
return exline
|
|
}
|
|
|
|
func (x *ExLine) TabComplete(tabComplete func(context.Context, string) ([]opt.Completion, string)) {
|
|
x.input.TabComplete(
|
|
tabComplete,
|
|
config.Ui.CompletionDelay,
|
|
config.Ui.CompletionMinChars,
|
|
&config.Binds.Global.CompleteKey,
|
|
)
|
|
}
|
|
|
|
func NewPrompt(prompt string, commit func(text string),
|
|
tabcomplete func(ctx context.Context, cmd string) ([]opt.Completion, string),
|
|
) *ExLine {
|
|
input := ui.NewTextInput("", config.Ui).Prompt(prompt)
|
|
if config.Ui.CompletionPopovers {
|
|
input.TabComplete(
|
|
tabcomplete,
|
|
config.Ui.CompletionDelay,
|
|
config.Ui.CompletionMinChars,
|
|
&config.Binds.Global.CompleteKey,
|
|
)
|
|
}
|
|
exline := &ExLine{
|
|
commit: commit,
|
|
tabcomplete: tabcomplete,
|
|
cmdHistory: &nullHistory{input: input},
|
|
input: input,
|
|
}
|
|
return exline
|
|
}
|
|
|
|
func (ex *ExLine) Invalidate() {
|
|
ui.Invalidate()
|
|
}
|
|
|
|
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 vaxis.Event) bool {
|
|
if key, ok := event.(vaxis.Key); ok {
|
|
switch {
|
|
case key.Matches(vaxis.KeyEnter), key.Matches('j', vaxis.ModCtrl):
|
|
cmd := ex.input.String()
|
|
ex.input.Focus(false)
|
|
ex.commit(cmd)
|
|
ex.finish()
|
|
case key.Matches(vaxis.KeyUp):
|
|
ex.input.Set(ex.cmdHistory.Prev())
|
|
ex.Invalidate()
|
|
case key.Matches(vaxis.KeyDown):
|
|
ex.input.Set(ex.cmdHistory.Next())
|
|
ex.Invalidate()
|
|
case key.Matches(vaxis.KeyEsc), key.Matches('c', vaxis.ModCtrl):
|
|
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() {}
|