~rjarry/aerc-devel

aerc: binds: refactor parser to be more tolerant v2 APPLIED

Tim Culverhouse: 2
 binds: refactor parser to be more tolerant
 ui: enable CSIu key encoding

 4 files changed, 72 insertions(+), 274 deletions(-)
#1153806 alpine-edge.yml success
#1153807 openbsd.yml success
aerc/patches: SUCCESS in 2m51s

[binds: refactor parser to be more tolerant][0] v2 from [Tim Culverhouse][1]

[0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/49698
[1]: mailto:tim@timculverhouse.com

✓ #1153807 SUCCESS aerc/patches/openbsd.yml     https://builds.sr.ht/~rjarry/job/1153807
✓ #1153806 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1153806
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~rjarry/aerc-devel/patches/49698/mbox | git am -3
Learn more about email & git

[PATCH aerc v2 1/2] binds: refactor parser to be more tolerant Export this patch

Refactor the bind parser to construct arbitrary modified keys instead of
only relying on built in maps. Add additional tests to cover edge cases.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
---
v2: introduce this entire patch
 config/binds.go      | 141 +++++++++++----------------------
 config/binds_test.go |  13 +++-
 doc/aerc-binds.5.scd | 182 ++-----------------------------------------
 3 files changed, 64 insertions(+), 272 deletions(-)

diff --git a/config/binds.go b/config/binds.go
index 95fa8c7d7e1f..3ddc25786022 100644
--- a/config/binds.go
+++ b/config/binds.go
@@ -10,6 +10,7 @@ import (
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"

	"git.sr.ht/~rjarry/aerc/lib/log"
	"git.sr.ht/~rockorager/vaxis"
@@ -474,10 +475,8 @@ func FormatKeyStrokes(keystrokes []KeyStroke) string {
		for name, ks := range keyNames {
			if ks.Modifiers == stroke.Modifiers && ks.Key == stroke.Key {
				switch name {
				case "cr", "c-m":
				case "cr":
					s = "<enter>"
				case "c-i":
					s = "<tab>"
				case "space":
					s = " "
				case "semicolon":
@@ -485,9 +484,21 @@ func FormatKeyStrokes(keystrokes []KeyStroke) string {
				default:
					s = fmt.Sprintf("<%s>", name)
				}
				// remove any modifiers this named key comes
				// with so we format properly
				stroke.Modifiers &^= ks.Modifiers
				break
			}
		}
		if stroke.Modifiers&vaxis.ModCtrl > 0 {
			sb.WriteString("c-")
		}
		if stroke.Modifiers&vaxis.ModAlt > 0 {
			sb.WriteString("a-")
		}
		if stroke.Modifiers&vaxis.ModShift > 0 {
			sb.WriteString("s-")
		}
		if s == "" && stroke.Key < unicode.MaxRune {
			s = string(stroke.Key)
		}
@@ -512,37 +523,21 @@ var keyNames = map[string]KeyStroke{
	"space":     {vaxis.ModifierMask(0), ' '},
	"semicolon": {vaxis.ModifierMask(0), ';'},
	"enter":     {vaxis.ModifierMask(0), vaxis.KeyEnter},
	"c-enter":   {vaxis.ModCtrl, vaxis.KeyEnter},
	"a-enter":   {vaxis.ModAlt, vaxis.KeyEnter},
	"up":        {vaxis.ModifierMask(0), vaxis.KeyUp},
	"c-up":      {vaxis.ModCtrl, vaxis.KeyUp},
	"a-up":      {vaxis.ModAlt, vaxis.KeyUp},
	"down":      {vaxis.ModifierMask(0), vaxis.KeyDown},
	"c-down":    {vaxis.ModCtrl, vaxis.KeyDown},
	"a-down":    {vaxis.ModAlt, vaxis.KeyDown},
	"right":     {vaxis.ModifierMask(0), vaxis.KeyRight},
	"c-right":   {vaxis.ModCtrl, vaxis.KeyRight},
	"a-right":   {vaxis.ModAlt, vaxis.KeyRight},
	"left":      {vaxis.ModifierMask(0), vaxis.KeyLeft},
	"c-left":    {vaxis.ModCtrl, vaxis.KeyLeft},
	"a-left":    {vaxis.ModAlt, vaxis.KeyLeft},
	"upleft":    {vaxis.ModifierMask(0), vaxis.KeyUpLeft},
	"upright":   {vaxis.ModifierMask(0), vaxis.KeyUpRight},
	"downleft":  {vaxis.ModifierMask(0), vaxis.KeyDownLeft},
	"downright": {vaxis.ModifierMask(0), vaxis.KeyDownRight},
	"center":    {vaxis.ModifierMask(0), vaxis.KeyCenter},
	"pgup":      {vaxis.ModifierMask(0), vaxis.KeyPgUp},
	"c-pgup":    {vaxis.ModCtrl, vaxis.KeyPgUp},
	"a-pgup":    {vaxis.ModAlt, vaxis.KeyPgUp},
	"pgdn":      {vaxis.ModifierMask(0), vaxis.KeyPgDown},
	"c-pgdn":    {vaxis.ModCtrl, vaxis.KeyPgDown},
	"a-pgdn":    {vaxis.ModAlt, vaxis.KeyPgDown},
	"home":      {vaxis.ModifierMask(0), vaxis.KeyHome},
	"end":       {vaxis.ModifierMask(0), vaxis.KeyEnd},
	"insert":    {vaxis.ModifierMask(0), vaxis.KeyInsert},
	"delete":    {vaxis.ModifierMask(0), vaxis.KeyDelete},
	"c-delete":  {vaxis.ModCtrl, vaxis.KeyDelete},
	"a-delete":  {vaxis.ModAlt, vaxis.KeyDelete},
	"backspace": {vaxis.ModifierMask(0), vaxis.KeyBackspace},
	// "help":      {vaxis.ModifierMask(0), vaxis.KeyHelp},
	"exit":    {vaxis.ModifierMask(0), vaxis.KeyExit},
@@ -614,80 +609,6 @@ var keyNames = map[string]KeyStroke{
	"f61":     {vaxis.ModifierMask(0), vaxis.KeyF61},
	"f62":     {vaxis.ModifierMask(0), vaxis.KeyF62},
	"f63":     {vaxis.ModifierMask(0), vaxis.KeyF63},
	"c-space": {vaxis.ModCtrl, ' '},
	"c-a":     {vaxis.ModCtrl, 'a'},
	"c-b":     {vaxis.ModCtrl, 'b'},
	"c-c":     {vaxis.ModCtrl, 'c'},
	"c-d":     {vaxis.ModCtrl, 'd'},
	"c-e":     {vaxis.ModCtrl, 'e'},
	"c-f":     {vaxis.ModCtrl, 'f'},
	"c-g":     {vaxis.ModCtrl, 'g'},
	"c-h":     {vaxis.ModCtrl, 'h'},
	"c-i":     {vaxis.ModCtrl, 'i'},
	"c-j":     {vaxis.ModCtrl, 'j'},
	"c-k":     {vaxis.ModCtrl, 'k'},
	"c-l":     {vaxis.ModCtrl, 'l'},
	"c-m":     {vaxis.ModCtrl, 'm'},
	"c-n":     {vaxis.ModCtrl, 'n'},
	"c-o":     {vaxis.ModCtrl, 'o'},
	"c-p":     {vaxis.ModCtrl, 'p'},
	"c-q":     {vaxis.ModCtrl, 'q'},
	"c-r":     {vaxis.ModCtrl, 'r'},
	"c-s":     {vaxis.ModCtrl, 's'},
	"c-t":     {vaxis.ModCtrl, 't'},
	"c-u":     {vaxis.ModCtrl, 'u'},
	"c-v":     {vaxis.ModCtrl, 'v'},
	"c-w":     {vaxis.ModCtrl, 'w'},
	"c-x":     {vaxis.ModCtrl, 'x'},
	"c-y":     {vaxis.ModCtrl, 'y'},
	"c-z":     {vaxis.ModCtrl, 'z'},
	"c-]":     {vaxis.ModCtrl, ']'},
	"c-\\":    {vaxis.ModCtrl, '\\'},
	"c-[":     {vaxis.ModCtrl, '['},
	"c-^":     {vaxis.ModCtrl, '^'},
	"c-_":     {vaxis.ModCtrl, '_'},
	"a-space": {vaxis.ModAlt, ' '},
	"a-0":     {vaxis.ModAlt, '0'},
	"a-1":     {vaxis.ModAlt, '1'},
	"a-2":     {vaxis.ModAlt, '2'},
	"a-3":     {vaxis.ModAlt, '3'},
	"a-4":     {vaxis.ModAlt, '4'},
	"a-5":     {vaxis.ModAlt, '5'},
	"a-6":     {vaxis.ModAlt, '6'},
	"a-7":     {vaxis.ModAlt, '7'},
	"a-8":     {vaxis.ModAlt, '8'},
	"a-9":     {vaxis.ModAlt, '9'},
	"a-a":     {vaxis.ModAlt, 'a'},
	"a-b":     {vaxis.ModAlt, 'b'},
	"a-c":     {vaxis.ModAlt, 'c'},
	"a-d":     {vaxis.ModAlt, 'd'},
	"a-e":     {vaxis.ModAlt, 'e'},
	"a-f":     {vaxis.ModAlt, 'f'},
	"a-g":     {vaxis.ModAlt, 'g'},
	"a-h":     {vaxis.ModAlt, 'h'},
	"a-i":     {vaxis.ModAlt, 'i'},
	"a-j":     {vaxis.ModAlt, 'j'},
	"a-k":     {vaxis.ModAlt, 'k'},
	"a-l":     {vaxis.ModAlt, 'l'},
	"a-m":     {vaxis.ModAlt, 'm'},
	"a-n":     {vaxis.ModAlt, 'n'},
	"a-o":     {vaxis.ModAlt, 'o'},
	"a-p":     {vaxis.ModAlt, 'p'},
	"a-q":     {vaxis.ModAlt, 'q'},
	"a-r":     {vaxis.ModAlt, 'r'},
	"a-s":     {vaxis.ModAlt, 's'},
	"a-t":     {vaxis.ModAlt, 't'},
	"a-u":     {vaxis.ModAlt, 'u'},
	"a-v":     {vaxis.ModAlt, 'v'},
	"a-w":     {vaxis.ModAlt, 'w'},
	"a-x":     {vaxis.ModAlt, 'x'},
	"a-y":     {vaxis.ModAlt, 'y'},
	"a-z":     {vaxis.ModAlt, 'z'},
	"a-]":     {vaxis.ModAlt, ']'},
	"a-\\":    {vaxis.ModAlt, '\\'},
	"a-[":     {vaxis.ModAlt, '['},
	"a-^":     {vaxis.ModAlt, '^'},
	"a-_":     {vaxis.ModAlt, '_'},
	"nul":     {vaxis.ModCtrl, ' '},
	"soh":     {vaxis.ModCtrl, 'a'},
	"stx":     {vaxis.ModCtrl, 'b'},
@@ -747,10 +668,36 @@ func ParseKeyStrokes(keystrokes string) ([]KeyStroke, error) {
				return nil, errors.New("Expected a key name")
			}
			name = name[:len(name)-1]
			if key, ok := keyNames[strings.ToLower(name)]; ok {
				strokes = append(strokes, key)
			} else {
				return nil, fmt.Errorf("Unknown key '%s'", name)
			args := strings.Split(name, "-")
			// check if the last char was a '-' and we'll add it
			// back. We check for "--" in case it was an invalid
			// keystroke (ie <C->)
			if strings.HasSuffix(name, "--") {
				args = append(args, "-")
			}
			ks := KeyStroke{}
			for i, arg := range args {
				if i == len(args)-1 {
					key, ok := keyNames[strings.ToLower(arg)]
					if !ok {
						r, n := utf8.DecodeRuneInString(arg)
						if n != len(arg) {
							return nil, fmt.Errorf("Unknown key '%s'", name)
						}
						key = KeyStroke{Key: r}
					}
					ks.Key = key.Key
					ks.Modifiers |= key.Modifiers
					strokes = append(strokes, ks)
				}
				switch strings.ToLower(arg) {
				case "s", "S":
					ks.Modifiers |= vaxis.ModShift
				case "a", "A":
					ks.Modifiers |= vaxis.ModAlt
				case "c", "C":
					ks.Modifiers |= vaxis.ModCtrl
				}
			}
		case '>':
			return nil, errors.New("Found '>' without '<'")
diff --git a/config/binds_test.go b/config/binds_test.go
index a92cf22fda77..7d4cd7792811 100644
--- a/config/binds_test.go
+++ b/config/binds_test.go
@@ -13,7 +13,10 @@ func TestGetBinding(t *testing.T) {

	bindings := NewKeyBindings()
	add := func(binding, cmd string) {
		b, _ := ParseBinding(binding, cmd, "")
		b, err := ParseBinding(binding, cmd, "")
		if err != nil {
			t.Fatal(err)
		}
		bindings.Add(b)
	}

@@ -58,6 +61,8 @@ func TestGetBinding(t *testing.T) {
	add("<C-Down>", ":next")
	add("<C-PgUp>", ":prev")
	add("<C-Enter>", ":open")
	add("<C-->", ":open")
	add("<S-up>", ":open")
	test([]KeyStroke{
		{vaxis.ModCtrl, 'a'},
	}, BINDING_FOUND, "c-a")
@@ -73,4 +78,10 @@ func TestGetBinding(t *testing.T) {
	test([]KeyStroke{
		{vaxis.ModCtrl, vaxis.KeyEnter},
	}, BINDING_FOUND, ":open")
	test([]KeyStroke{
		{vaxis.ModCtrl, '-'},
	}, BINDING_FOUND, ":open")
	test([]KeyStroke{
		{vaxis.ModShift, vaxis.KeyUp},
	}, BINDING_FOUND, ":open")
}
diff --git a/doc/aerc-binds.5.scd b/doc/aerc-binds.5.scd
index a46b6427cd0b..de8f436c19f0 100644
--- a/doc/aerc-binds.5.scd
+++ b/doc/aerc-binds.5.scd
@@ -147,8 +147,14 @@ available in each binding context:
# SUPPORTED KEYS

In addition to letters and some characters (e.g. *a*, *RR*, *gu*, *?*, *!*,
etc.), special keys may be specified in *<angle brackets>*. The following
special keys are supported:
etc.), special keys may be specified in *<angle brackets>*. The syntax for
modified or special keys is:

	<C-A-S-key>

Where C is control, A is alt, S is shift, and key is the named key or character.

Valid key names are:

[[ *Name*
:- *Description*
@@ -162,40 +168,16 @@ special keys are supported:
:  Enter
|  *<up>*
:  Up arrow
|  *<c-up>*
:  Ctrl+Up
|  *<a-up>*
:  Alt+Up
|  *<down>*
:  Down arrow
|  *<c-down>*
:  Ctrl+Down
|  *<a-down>*
:  Alt+Down
|  *<right>*
:  Right arrow
|  *<c-right>*
:  Ctrl+Right
|  *<a-right>*
:  Alt+Right
|  *<left>*
:  Left arrow
|  *<c-left>*
:  Ctrl+Left
|  *<a-left>*
:  Alt+Left
|  *<pgup>*
:  Page Up
|  *<c-pgup>*
:  Ctrl+PageUp
|  *<a-pgup>*
:  Alt+PageUp
|  *<pgdn>*
:  Page Down
|  *<c-pgdn>*
:  Ctrl+PageDn
|  *<a-pgdn>*
:  Alt+PageDn
|  *<home>*
:  Home
|  *<end>*
@@ -204,10 +186,6 @@ special keys are supported:
:  Insert
|  *<delete>*
:  Delete
|  *<c-delete>*
:  Ctrl+Delete
|  *<a-delete>*
:  Alt+Delete
|  *<backspace>*
:  Backspace
|  *<exit>*
@@ -222,150 +200,6 @@ special keys are supported:
:  Shift+Tab
|  *<esc>*
:  Escape
|  *<c-space>*
:  Ctrl+Space
|  *<a-space>*
:  Alt+Space
|  *<a-0>*
:  Alt+0
|  *<a-1>*
:  Alt+1
|  *<a-2>*
:  Alt+2
|  *<a-3>*
:  Alt+3
|  *<a-4>*
:  Alt+4
|  *<a-5>*
:  Alt+5
|  *<a-6>*
:  Alt+6
|  *<a-7>*
:  Alt+7
|  *<a-8>*
:  Alt+8
|  *<a-9>*
:  Alt+9
|  *<c-a>*
:  Ctrl+a
|  *<a-a>*
:  Alt+a
|  *<c-b>*
:  Ctrl+b
|  *<a-b>*
:  Alt+b
|  *<c-c>*
:  Ctrl+c
|  *<a-c>*
:  Alt+c
|  *<c-d>*
:  Ctrl+d
|  *<a-d>*
:  Alt+d
|  *<c-e>*
:  Ctrl+e
|  *<a-e>*
:  Alt+e
|  *<c-f>*
:  Ctrl+f
|  *<a-f>*
:  Alt+f
|  *<c-g>*
:  Ctrl+g
|  *<a-g>*
:  Alt+g
|  *<c-h>*
:  Ctrl+h
|  *<a-h>*
:  Alt+h
|  *<c-i>*
:  Ctrl+i
|  *<a-i>*
:  Alt+i
|  *<c-j>*
:  Ctrl+j
|  *<a-j>*
:  Alt+j
|  *<c-k>*
:  Ctrl+k
|  *<a-k>*
:  Alt+k
|  *<c-l>*
:  Ctrl+l
|  *<a-l>*
:  Alt+l
|  *<c-m>*
:  Ctrl+m
|  *<a-m>*
:  Alt+m
|  *<c-n>*
:  Ctrl+n
|  *<a-n>*
:  Alt+n
|  *<c-o>*
:  Ctrl+o
|  *<a-o>*
:  Alt+o
|  *<c-p>*
:  Ctrl+p
|  *<a-p>*
:  Alt+p
|  *<c-q>*
:  Ctrl+q
|  *<a-q>*
:  Alt+q
|  *<c-r>*
:  Ctrl+r
|  *<a-r>*
:  Alt+r
|  *<c-s>*
:  Ctrl+s
|  *<a-s>*
:  Alt+s
|  *<c-t>*
:  Ctrl+t
|  *<a-t>*
:  Alt+t
|  *<c-u>*
:  Ctrl+u
|  *<a-u>*
:  Alt+u
|  *<c-v>*
:  Ctrl+v
|  *<a-v>*
:  Alt+v
|  *<c-w>*
:  Ctrl+w
|  *<a-w>*
:  Alt+w
|  *<c-x>*
:  Ctrl+x
|  *<a-x>*
:  Alt+x
|  *<c-y>*
:  Ctrl+y
|  *<a-y>*
:  Alt+y
|  *<c-z>*
:  Ctrl+z
|  *<a-z>*
:  Alt+z
|  *<c-]>*
:  Ctrl+]
|  *<a-]>*
:  Alt+]
|  *<c-[>*
:  Ctrl+[
|  *<a-[>*
:  Alt+[
|  *<c-^>*
:  Ctrl+^
|  *<a-^>*
:  Alt+^
|  *<c-\_>*
:  Ctrl+\_
|  *<a-\_>*
:  Alt+\_

# SEE ALSO

-- 
2.43.2
Tim Culverhouse <tim@timculverhouse.com> wrote:

[PATCH aerc v2 2/2] ui: enable CSIu key encoding Export this patch

Enable CSIu key encoding protocol when support is detected. This will
enable keybinds which traditionally have been unavailable due to
conflicting with other keys (C-i, C-m, C-[, etc).

Remove numlock and capslock from all keypresses to prevent interfering
with key matching.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
---
v2: remove numlock and capslock from modifiers (Robin)

 lib/ui/ui.go | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/ui/ui.go b/lib/ui/ui.go
index d63ebf36c4ca..3b1050b544da 100644
--- a/lib/ui/ui.go
+++ b/lib/ui/ui.go
@@ -49,8 +49,7 @@ var state struct {

func Initialize(content DrawableInteractive) error {
	opts := vaxis.Options{
		DisableMouse:         !config.Ui.MouseEnabled,
		DisableKittyKeyboard: true,
		DisableMouse: !config.Ui.MouseEnabled,
	}
	vx, err := vaxis.New(opts)
	if err != nil {
@@ -144,6 +143,13 @@ func HandleEvent(event vaxis.Event) {
	case vaxis.Redraw:
		Invalidate()
	default:
		// We never care about num or caps lock. Remove them so it
		// doesn't interefere with key matching
		if key, ok := event.(vaxis.Key); ok {
			key.Modifiers &^= vaxis.ModCapsLock
			key.Modifiers &^= vaxis.ModNumLock
			event = key
		}
		// if we have a popover, and it can handle the event, it does so
		if state.popover == nil || !state.popover.Event(event) {
			// otherwise, we send the event to the main content
-- 
2.43.2
aerc/patches: SUCCESS in 2m51s

[binds: refactor parser to be more tolerant][0] v2 from [Tim Culverhouse][1]

[0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/49698
[1]: mailto:tim@timculverhouse.com

✓ #1153807 SUCCESS aerc/patches/openbsd.yml     https://builds.sr.ht/~rjarry/job/1153807
✓ #1153806 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1153806