diff options
-rw-r--r-- | app/compose.go | 3 | ||||
-rw-r--r-- | app/exline.go | 3 | ||||
-rw-r--r-- | config/binds.conf | 1 | ||||
-rw-r--r-- | config/binds.go | 32 | ||||
-rw-r--r-- | doc/aerc-binds.5.scd | 6 | ||||
-rw-r--r-- | lib/ui/textinput.go | 30 |
6 files changed, 47 insertions, 28 deletions
diff --git a/app/compose.go b/app/compose.go index 9ab8206b..bf1d32cb 100644 --- a/app/compose.go +++ b/app/compose.go @@ -245,6 +245,7 @@ func (c *Composer) buildComposeHeader(cmpl *completer.Completer) { cmpl.ForHeader(h), uiConfig.CompletionDelay, uiConfig.CompletionMinChars, + &config.Binds.Compose.CompleteKey, ) } c.editors[h] = e @@ -277,6 +278,7 @@ func (c *Composer) buildComposeHeader(cmpl *completer.Completer) { cmpl.ForHeader(h), uiConfig.CompletionDelay, uiConfig.CompletionMinChars, + &config.Binds.Compose.CompleteKey, ) } c.editors[h] = e @@ -1420,6 +1422,7 @@ func (c *Composer) addEditor(header string, value string, appendHeader bool) str c.completer.ForHeader(header), uiConfig.CompletionDelay, uiConfig.CompletionMinChars, + &config.Binds.Compose.CompleteKey, ) } c.editors[header] = e diff --git a/app/exline.go b/app/exline.go index b941b100..61fc340a 100644 --- a/app/exline.go +++ b/app/exline.go @@ -26,6 +26,7 @@ func NewExLine(cmd string, commit func(cmd string), finish func(), tabcomplete, config.Ui.CompletionDelay, config.Ui.CompletionMinChars, + &config.Binds.Global.CompleteKey, ) } exline := &ExLine{ @@ -43,6 +44,7 @@ func (x *ExLine) TabComplete(tabComplete func(string) ([]string, string)) { tabComplete, config.Ui.CompletionDelay, config.Ui.CompletionMinChars, + &config.Binds.Global.CompleteKey, ) } @@ -55,6 +57,7 @@ func NewPrompt(prompt string, commit func(text string), tabcomplete, config.Ui.CompletionDelay, config.Ui.CompletionMinChars, + &config.Binds.Global.CompleteKey, ) } exline := &ExLine{ diff --git a/config/binds.conf b/config/binds.conf index a38795d5..58d81508 100644 --- a/config/binds.conf +++ b/config/binds.conf @@ -115,6 +115,7 @@ $ex = <C-x> # view $noinherit = true $ex = <C-x> +$complete = <C-o> <C-k> = :prev-field<Enter> <C-Up> = :prev-field<Enter> <C-j> = :next-field<Enter> diff --git a/config/binds.go b/config/binds.go index 4552030d..1ea36a2d 100644 --- a/config/binds.go +++ b/config/binds.go @@ -57,6 +57,8 @@ type KeyBindings struct { Globals bool // Which key opens the ex line (default is :) ExKey KeyStroke + // Which key triggers completion (default is <tab>) + CompleteKey KeyStroke // private contextualBinds []*BindingConfigContext @@ -154,7 +156,8 @@ func parseBinds(root string) error { func LoadBindingSection(sec *ini.Section) (*KeyBindings, error) { bindings := NewKeyBindings() for key, value := range sec.KeysHash() { - if key == "$ex" { + switch key { + case "$ex": strokes, err := ParseKeyStrokes(value) if err != nil { return nil, err @@ -163,9 +166,7 @@ func LoadBindingSection(sec *ini.Section) (*KeyBindings, error) { return nil, errors.New("Invalid binding") } bindings.ExKey = strokes[0] - continue - } - if key == "$noinherit" { + case "$noinherit": if value == "false" { continue } @@ -173,13 +174,22 @@ func LoadBindingSection(sec *ini.Section) (*KeyBindings, error) { return nil, errors.New("Invalid binding") } bindings.Globals = false - continue - } - binding, err := ParseBinding(key, value) - if err != nil { - return nil, err + case "$complete": + strokes, err := ParseKeyStrokes(value) + if err != nil { + return nil, err + } + if len(strokes) != 1 { + return nil, errors.New("Invalid binding") + } + bindings.CompleteKey = strokes[0] + default: + binding, err := ParseBinding(key, value) + if err != nil { + return nil, err + } + bindings.Add(binding) } - bindings.Add(binding) } return bindings, nil } @@ -266,6 +276,7 @@ func LoadBinds(binds *ini.File, baseName string, baseGroup **KeyBindings) error func NewKeyBindings() *KeyBindings { return &KeyBindings{ ExKey: KeyStroke{tcell.ModNone, tcell.KeyRune, ':'}, + CompleteKey: KeyStroke{tcell.ModNone, tcell.KeyTab, 0}, Globals: true, contextualCache: make(map[bindsContextKey]*KeyBindings), contextualCounts: make(map[bindsContextType]int), @@ -329,6 +340,7 @@ func MergeBindings(bindings ...*KeyBindings) *KeyBindings { } merged.Bindings = filterAndCleanBindings(merged.Bindings) merged.ExKey = bindings[0].ExKey + merged.CompleteKey = bindings[0].CompleteKey merged.Globals = bindings[0].Globals return merged } diff --git a/doc/aerc-binds.5.scd b/doc/aerc-binds.5.scd index 228c6cd1..99ef1188 100644 --- a/doc/aerc-binds.5.scd +++ b/doc/aerc-binds.5.scd @@ -122,6 +122,12 @@ available in each binding context: Default: _:_ +*$complete* = _<key-stroke>_ + This can be set to a keystroke which will trigger command completion in + this context for text inputs that support it. + + Default: _<tab>_ + # SUPPORTED KEYS In addition to letters and some characters (e.g. *a*, *RR*, *gu*, *?*, *!*, diff --git a/lib/ui/textinput.go b/lib/ui/textinput.go index dd946aec..4b051d88 100644 --- a/lib/ui/textinput.go +++ b/lib/ui/textinput.go @@ -35,6 +35,7 @@ type TextInput struct { completeDelay time.Duration completeDebouncer *time.Timer completeMinChars int + completeKey *config.KeyStroke uiConfig *config.UIConfig } @@ -62,12 +63,12 @@ func (ti *TextInput) Prompt(prompt string) *TextInput { func (ti *TextInput) TabComplete( tabcomplete func(s string) ([]string, string), - d time.Duration, - minChars int, + d time.Duration, minChars int, key *config.KeyStroke, ) *TextInput { ti.tabcomplete = tabcomplete ti.completeDelay = d ti.completeMinChars = minChars + ti.completeKey = key return ti } @@ -344,55 +345,48 @@ func (ti *TextInput) Event(event tcell.Event) bool { ti.Lock() defer ti.Unlock() if event, ok := event.(*tcell.EventKey); ok { + c := ti.completeKey + if c != nil && c.Key == event.Key() && c.Modifiers == event.Modifiers() { + ti.showCompletions() + return true + } + + ti.invalidateCompletions() + switch event.Key() { case tcell.KeyBackspace, tcell.KeyBackspace2: - ti.invalidateCompletions() ti.backspace() case tcell.KeyCtrlD, tcell.KeyDelete: - ti.invalidateCompletions() ti.deleteChar() case tcell.KeyCtrlB, tcell.KeyLeft: - ti.invalidateCompletions() if ti.index > 0 { ti.index-- ti.ensureScroll() ti.Invalidate() } case tcell.KeyCtrlF, tcell.KeyRight: - ti.invalidateCompletions() if ti.index < len(ti.text) { ti.index++ ti.ensureScroll() ti.Invalidate() } case tcell.KeyCtrlA, tcell.KeyHome: - ti.invalidateCompletions() ti.index = 0 ti.ensureScroll() ti.Invalidate() case tcell.KeyCtrlE, tcell.KeyEnd: - ti.invalidateCompletions() ti.index = len(ti.text) ti.ensureScroll() ti.Invalidate() case tcell.KeyCtrlK: - ti.invalidateCompletions() ti.deleteLineForward() case tcell.KeyCtrlW: - ti.invalidateCompletions() ti.deleteWord() case tcell.KeyCtrlU: - ti.invalidateCompletions() ti.deleteLineBackward() case tcell.KeyESC: - if ti.completions != nil { - ti.invalidateCompletions() - ti.Invalidate() - } - case tcell.KeyTab: - ti.showCompletions() + ti.Invalidate() case tcell.KeyRune: - ti.invalidateCompletions() ti.insert(event.Rune()) } } |