aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2023-08-12 00:51:41 +0200
committerRobin Jarry <robin@jarry.cc>2023-10-30 23:24:43 +0100
commit41c368d63485531927efd4161f452fada83e6b38 (patch)
tree198f9662e867d4087f8474b5a70d1cd57d6fd7d7
parentd4c9d0a28adfa04f22d302a7976b3e4777924786 (diff)
downloadaerc-41c368d63485531927efd4161f452fada83e6b38.tar.gz
aerc-41c368d63485531927efd4161f452fada83e6b38.zip
complete: allow disabling automatic completion
Allow setting complete-min-chars = 0 to disable automatic completion. By default, the available completion choices can be displayed with <tab> or <c-o> when in the composer. These keys may be configured using the special $complete entry in binds.conf. Signed-off-by: Robin Jarry <robin@jarry.cc>
-rw-r--r--app/compose.go3
-rw-r--r--app/exline.go3
-rw-r--r--config/binds.conf1
-rw-r--r--config/binds.go32
-rw-r--r--doc/aerc-binds.5.scd6
-rw-r--r--doc/aerc-config.5.scd4
-rw-r--r--lib/ui/textinput.go32
7 files changed, 52 insertions, 29 deletions
diff --git a/app/compose.go b/app/compose.go
index 101a5765..60e17cf4 100644
--- a/app/compose.go
+++ b/app/compose.go
@@ -239,6 +239,7 @@ func (c *Composer) buildComposeHeader(cmpl *completer.Completer) {
cmpl.ForHeader(h),
uiConfig.CompletionDelay,
uiConfig.CompletionMinChars,
+ &config.Binds.Compose.CompleteKey,
)
}
c.editors[h] = e
@@ -271,6 +272,7 @@ func (c *Composer) buildComposeHeader(cmpl *completer.Completer) {
cmpl.ForHeader(h),
uiConfig.CompletionDelay,
uiConfig.CompletionMinChars,
+ &config.Binds.Compose.CompleteKey,
)
}
c.editors[h] = e
@@ -1414,6 +1416,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 c0e28af9..147f0559 100644
--- a/config/binds.conf
+++ b/config/binds.conf
@@ -114,6 +114,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 1b2799f2..bc77e655 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),
@@ -281,6 +292,7 @@ func MergeBindings(bindings ...*KeyBindings) *KeyBindings {
}
}
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 8ce59cf0..a989cd05 100644
--- a/doc/aerc-binds.5.scd
+++ b/doc/aerc-binds.5.scd
@@ -103,6 +103,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/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index a45e2443..36514c1f 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -283,6 +283,10 @@ These options are configured in the *[ui]* section of _aerc.conf_.
The minimum required characters to allow auto-completion to be triggered
after *completion-delay*.
+ Setting this to _0_ disables automatic completion, leaving only the
+ manually triggered completion with the *$complete* key (see
+ *aerc-binds*(5) for more details).
+
Default: _1_
*border-char-vertical* = _"<char>"_++
diff --git a/lib/ui/textinput.go b/lib/ui/textinput.go
index dd946aec..ab448d59 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
}
@@ -303,7 +304,7 @@ func (ti *TextInput) onFocusLost() {
}
func (ti *TextInput) updateCompletions() {
- if ti.tabcomplete == nil {
+ if ti.tabcomplete == nil || ti.completeMinChars == 0 {
// no completer
return
}
@@ -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())
}
}