Add :prompt command

Usage:
    :prompt <prompt> <command...>

Displays the prompt on the status bar, waits for user input, then
appends that input as the last argument to the command and executes it.
The input is passed as one argument to the command, unless it is empty,
in which case no extra argument is added.
This commit is contained in:
Christopher Vittal 2019-08-19 21:56:12 -04:00 committed by Drew DeVault
parent ea4fe71360
commit ecd803aae4
4 changed files with 108 additions and 6 deletions

33
commands/prompt.go Normal file
View file

@ -0,0 +1,33 @@
package commands
import (
"errors"
"fmt"
"git.sr.ht/~sircmpwn/aerc/widgets"
)
type Prompt struct{}
func init() {
register(Prompt{})
}
func (_ Prompt) Aliases() []string {
return []string{"prompt"}
}
func (_ Prompt) Complete(aerc *widgets.Aerc, args []string) []string {
return nil // TODO: add completions
}
func (_ Prompt) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) < 3 {
return errors.New(fmt.Sprintf("Usage: %s <prompt> <cmd>", args[0]))
}
prompt := args[1]
cmd := args[2:]
aerc.RegisterPrompt(prompt, cmd)
return nil
}

View file

@ -67,6 +67,12 @@ These commands work in any context.
Cycles to the previous or next tab in the list, repeating n times
(default: 1).
*prompt* <prompt> <command...>
Displays the prompt on the status bar, waits for user input, then appends
that input as the last argument to the command and executes it. The input is
passed as one argument to the command, unless it is empty, in which case no
extra argument is added.
*quit*
Exits aerc.

View file

@ -30,6 +30,7 @@ type Aerc struct {
statusbar *libui.Stack
statusline *StatusLine
pendingKeys []config.KeyStroke
prompts *libui.Stack
tabs *libui.Tabs
beep func() error
}
@ -65,6 +66,7 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
logger: logger,
statusbar: statusbar,
statusline: statusline,
prompts: libui.NewStack(),
tabs: tabs,
}
@ -105,6 +107,20 @@ func (aerc *Aerc) Tick() bool {
for _, acct := range aerc.accounts {
more = acct.Tick() || more
}
if len(aerc.prompts.Children()) > 0 {
more = true
previous := aerc.focused
prompt := aerc.prompts.Pop().(*ExLine)
prompt.finish = func() {
aerc.statusbar.Pop()
aerc.focus(previous)
}
aerc.statusbar.Push(prompt)
aerc.focus(prompt)
}
return more
}
@ -358,8 +374,6 @@ func (aerc *Aerc) BeginExCommand() {
if aerc.simulating == 0 {
aerc.cmdHistory.Add(cmd)
}
aerc.statusbar.Pop()
aerc.focus(previous)
}, func() {
aerc.statusbar.Pop()
aerc.focus(previous)
@ -370,6 +384,22 @@ func (aerc *Aerc) BeginExCommand() {
aerc.focus(exline)
}
func (aerc *Aerc) RegisterPrompt(prompt string, cmd []string) {
p := NewPrompt(prompt, func(text string) {
if text != "" {
cmd = append(cmd, text)
}
err := aerc.cmd(cmd)
if err != nil {
aerc.PushStatus(" "+err.Error(), 10*time.Second).
Color(tcell.ColorDefault, tcell.ColorRed)
}
}, func(cmd string) []string {
return nil // TODO: completions
})
aerc.prompts.Push(p)
}
func (aerc *Aerc) Mailto(addr *url.URL) error {
acct := aerc.SelectedAccount()
if acct == nil {

View file

@ -9,21 +9,21 @@ import (
type ExLine struct {
ui.Invalidatable
cancel func()
commit func(cmd string)
finish func()
tabcomplete func(cmd string) []string
cmdHistory lib.History
input *ui.TextInput
}
func NewExLine(commit func(cmd string), cancel func(),
func NewExLine(commit func(cmd string), finish func(),
tabcomplete func(cmd string) []string,
cmdHistory lib.History) *ExLine {
input := ui.NewTextInput("").Prompt(":").TabComplete(tabcomplete)
exline := &ExLine{
cancel: cancel,
commit: commit,
finish: finish,
tabcomplete: tabcomplete,
cmdHistory: cmdHistory,
input: input,
@ -34,6 +34,22 @@ func NewExLine(commit func(cmd string), cancel func(),
return exline
}
func NewPrompt(prompt string, commit func(text string),
tabcomplete func(cmd string) []string) *ExLine {
input := ui.NewTextInput("").Prompt(prompt).TabComplete(tabcomplete)
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)
}
@ -54,6 +70,7 @@ func (ex *ExLine) Event(event tcell.Event) bool {
cmd := ex.input.String()
ex.input.Focus(false)
ex.commit(cmd)
ex.finish()
case tcell.KeyUp:
ex.input.Set(ex.cmdHistory.Prev())
ex.Invalidate()
@ -63,10 +80,26 @@ func (ex *ExLine) Event(event tcell.Event) bool {
case tcell.KeyEsc, tcell.KeyCtrlC:
ex.input.Focus(false)
ex.cmdHistory.Reset()
ex.cancel()
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() {}