viewer: add key passthrough mode

When trying to search in less, keys bound to viewer functions can't be
used as part of the search query, which makes the search useless.

Add a view::passthrough binding mode and a :toggle-key-passthrough
command go toggle in and out of that mode. By default, typing '/' in the
viewer is bound to enabling key passthrough and automatically inserting
'/', to easily enter "less" search mode. When in the passthrough mode,
all bindings are ignored by default. The default binds.conf only defines
a single keybinding in that mode: <Esc> to get back out. $ex is bound to
<C-x> to allow typing colons.

Signed-off-by: Kt Programs <ktprograms@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
kt programs 2022-03-14 11:03:34 +08:00 committed by Robin Jarry
parent 4bc43d2741
commit 74366d895d
6 changed files with 91 additions and 24 deletions

View file

@ -0,0 +1,35 @@
package msgview
import (
"errors"
"git.sr.ht/~rjarry/aerc/widgets"
)
type ToggleKeyPassthrough struct{}
func init() {
register(ToggleKeyPassthrough{})
}
func (ToggleKeyPassthrough) Aliases() []string {
return []string{"toggle-key-passthrough"}
}
func (ToggleKeyPassthrough) Complete(aerc *widgets.Aerc, args []string) []string {
return nil
}
func (ToggleKeyPassthrough) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: toggle-key-passthrough")
}
mv, _ := aerc.SelectedTab().(*widgets.MessageViewer)
keyPassthroughEnabled := mv.ToggleKeyPassthrough()
if keyPassthroughEnabled {
aerc.SetExtraStatus("[passthrough]")
} else {
aerc.ClearExtraStatus()
}
return nil
}

View file

@ -56,6 +56,7 @@ N = :prev-result<Enter>
<Esc> = :clear<Enter> <Esc> = :clear<Enter>
[view] [view]
/ = :toggle-key-passthrough<Enter>/
q = :close<Enter> q = :close<Enter>
| = :pipe<space> | = :pipe<space>
D = :delete<Enter> D = :delete<Enter>
@ -74,6 +75,11 @@ H = :toggle-headers<Enter>
J = :next<Enter> J = :next<Enter>
K = :prev<Enter> K = :prev<Enter>
[view::passthrough]
$noinherit = true
$ex = <C-x>
<Esc> = :toggle-key-passthrough<Enter>
[compose] [compose]
# Keybindings used when the embedded terminal is not selected in the compose # Keybindings used when the embedded terminal is not selected in the compose
# view # view

View file

@ -112,6 +112,7 @@ type BindingConfig struct {
ComposeReview *KeyBindings ComposeReview *KeyBindings
MessageList *KeyBindings MessageList *KeyBindings
MessageView *KeyBindings MessageView *KeyBindings
MessageViewPassthrough *KeyBindings
Terminal *KeyBindings Terminal *KeyBindings
} }
@ -143,6 +144,7 @@ type ViewerConfig struct {
ShowHeaders bool `ini:"show-headers"` ShowHeaders bool `ini:"show-headers"`
AlwaysShowMime bool `ini:"always-show-mime"` AlwaysShowMime bool `ini:"always-show-mime"`
HeaderLayout [][]string `ini:"-"` HeaderLayout [][]string `ini:"-"`
KeyPassthrough bool `ini:"-"`
} }
type TriggersConfig struct { type TriggersConfig struct {
@ -598,6 +600,7 @@ func LoadConfigFromFile(root *string, logger *log.Logger) (*AercConfig, error) {
ComposeReview: NewKeyBindings(), ComposeReview: NewKeyBindings(),
MessageList: NewKeyBindings(), MessageList: NewKeyBindings(),
MessageView: NewKeyBindings(), MessageView: NewKeyBindings(),
MessageViewPassthrough: NewKeyBindings(),
Terminal: NewKeyBindings(), Terminal: NewKeyBindings(),
}, },
@ -708,6 +711,7 @@ func LoadConfigFromFile(root *string, logger *log.Logger) (*AercConfig, error) {
"messages": &config.Bindings.MessageList, "messages": &config.Bindings.MessageList,
"terminal": &config.Bindings.Terminal, "terminal": &config.Bindings.Terminal,
"view": &config.Bindings.MessageView, "view": &config.Bindings.MessageView,
"view::passthrough": &config.Bindings.MessageViewPassthrough,
"compose::editor": &config.Bindings.ComposeEditor, "compose::editor": &config.Bindings.ComposeEditor,
"compose::review": &config.Bindings.ComposeReview, "compose::review": &config.Bindings.ComposeReview,
} }

View file

@ -564,6 +564,10 @@ are:
*[view]* *[view]*
keybindings for the message viewer keybindings for the message viewer
*[view::passthrough]*
keybindings for the viewer, when in key passthrough mode
(toggled with :toggle-key-passthrough)
*[compose]* *[compose]*
keybindings for the message composer keybindings for the message composer

View file

@ -201,7 +201,12 @@ func (aerc *Aerc) getBindings() *config.KeyBindings {
return aerc.conf.MergeContextualBinds(aerc.conf.Bindings.Compose, config.BIND_CONTEXT_ACCOUNT, selectedAccountName, "compose") return aerc.conf.MergeContextualBinds(aerc.conf.Bindings.Compose, config.BIND_CONTEXT_ACCOUNT, selectedAccountName, "compose")
} }
case *MessageViewer: case *MessageViewer:
switch view.Bindings() {
case "view::passthrough":
return aerc.conf.MergeContextualBinds(aerc.conf.Bindings.MessageViewPassthrough, config.BIND_CONTEXT_ACCOUNT, selectedAccountName, "view::passthrough")
default:
return aerc.conf.MergeContextualBinds(aerc.conf.Bindings.MessageView, config.BIND_CONTEXT_ACCOUNT, selectedAccountName, "view") return aerc.conf.MergeContextualBinds(aerc.conf.Bindings.MessageView, config.BIND_CONTEXT_ACCOUNT, selectedAccountName, "view")
}
case *Terminal: case *Terminal:
return aerc.conf.Bindings.Terminal return aerc.conf.Bindings.Terminal
default: default:

View file

@ -286,6 +286,11 @@ func (mv *MessageViewer) ToggleHeaders() {
switcher.Invalidate() switcher.Invalidate()
} }
func (mv *MessageViewer) ToggleKeyPassthrough() bool {
mv.conf.Viewer.KeyPassthrough = !mv.conf.Viewer.KeyPassthrough
return mv.conf.Viewer.KeyPassthrough
}
func (mv *MessageViewer) SelectedMessagePart() *PartInfo { func (mv *MessageViewer) SelectedMessagePart() *PartInfo {
switcher := mv.switcher switcher := mv.switcher
part := switcher.parts[switcher.selected] part := switcher.parts[switcher.selected]
@ -325,6 +330,14 @@ func (mv *MessageViewer) NextPart() {
mv.Invalidate() mv.Invalidate()
} }
func (mv *MessageViewer) Bindings() string {
if mv.conf.Viewer.KeyPassthrough {
return "view::passthrough"
} else {
return "view"
}
}
func (mv *MessageViewer) Close() error { func (mv *MessageViewer) Close() error {
mv.switcher.Cleanup() mv.switcher.Cleanup()
return nil return nil