From 51d55bb102c8ebb08aa28b1bae558ababb7566f6 Mon Sep 17 00:00:00 2001 From: augustus Date: Sat, 2 Jul 2022 17:07:55 +0100 Subject: [PATCH] Fix panic on Ctrl+Arrow I often hit fn+arrow up / down to page up / down. If I accidentally hit ctrl gomu panics. Investigated it today and the issue is the rune extraction -- it assumes we'll always have Ctrl+ but in the case of an arrow key we have Ctrl+Up or Ctrl+Down. Essentially this simply checks if the regex found any matches, if not we return not result akin to a failed map lookup. I considered raising an error, but that would be just as annoying as a panic when I fat finger Ctrl :) ```golang panic: runtime error: index out of range [0] with length 0 [recovered] panic: runtime error: index out of range [0] with length 0 goroutine 1 [running]: github.com/rivo/tview.(*Application).Run.func1() /home/augustus/go/pkg/mod/github.com/rivo/tview@v0.0.0-20210312174852-ae9464cc3598/application.go:243 +0x4d panic({0xadb840, 0xc00076a000}) /usr/local/go/src/runtime/panic.go:1038 +0x215 github.com/issadarkthing/gomu/anko.extractCtrlRune({0xc00003cc90, 0x9}) /home/augustus/go/src/github.com/issadarkthing/gomu/anko/anko.go:216 +0x75 github.com/issadarkthing/gomu/anko.(*Anko).KeybindExists(0xb23243, {0xb2591b, 0x6}, 0xc00007e040) /home/augustus/go/src/github.com/issadarkthing/gomu/anko/anko.go:158 +0x78 main.start.func4(0xc00007e040) /home/augustus/go/src/github.com/issadarkthing/gomu/start.go:516 +0x14b github.com/rivo/tview.(*Application).Run(0xc00023e2a0) /home/augustus/go/pkg/mod/github.com/rivo/tview@v0.0.0-20210312174852-ae9464cc3598/application.go:318 +0x6d2 main.start(0xc00023e2a0, {0xc00028e840, 0xc00003d4b6, 0xc00028e850, 0xc00003d4b7}) /home/augustus/go/src/github.com/issadarkthing/gomu/start.go:546 +0xceb main.main() /home/augustus/go/src/github.com/issadarkthing/gomu/main.go:21 +0x10e ``` --- anko/anko.go | 34 ++++++++++++++++++++++++++-------- anko/anko_test.go | 34 ++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/anko/anko.go b/anko/anko.go index a8c82da5..8df7bfbc 100644 --- a/anko/anko.go +++ b/anko/anko.go @@ -155,12 +155,18 @@ func (a *Anko) KeybindExists(panel string, eventKey *tcell.EventKey) bool { name := eventKey.Name() if strings.Contains(name, "Ctrl") { - key := extractCtrlRune(name) + key, ok := extractCtrlRune(name) + if !ok { + return false + } src = fmt.Sprintf("Keybinds.%s[\"ctrl_%s\"]", panel, strings.ToLower(string(key))) } else if strings.Contains(name, "Alt") { - key := extractAltRune(name) + key, ok := extractAltRune(name) + if !ok { + return false + } src = fmt.Sprintf("Keybinds.%s[\"alt_%c\"]", panel, key) } else if strings.Contains(name, "Rune") { @@ -186,12 +192,18 @@ func (a *Anko) ExecKeybind(panel string, eventKey *tcell.EventKey) error { name := eventKey.Name() if strings.Contains(name, "Ctrl") { - key := extractCtrlRune(name) + key, ok := extractCtrlRune(name) + if !ok { + return nil + } src = fmt.Sprintf("Keybinds.%s[\"ctrl_%s\"]()", panel, strings.ToLower(string(key))) } else if strings.Contains(name, "Alt") { - key := extractAltRune(name) + key, ok := extractAltRune(name) + if !ok { + return nil + } src = fmt.Sprintf("Keybinds.%s[\"alt_%c\"]()", panel, key) } else if strings.Contains(name, "Rune") { @@ -210,14 +222,20 @@ func (a *Anko) ExecKeybind(panel string, eventKey *tcell.EventKey) error { return nil } -func extractCtrlRune(str string) rune { +func extractCtrlRune(str string) (rune, bool) { re := regexp.MustCompile(`\+(.)$`) x := re.FindStringSubmatch(str) - return rune(x[0][1]) + if len(x) == 0 { + return rune(' '), false + } + return rune(x[0][1]), true } -func extractAltRune(str string) rune { +func extractAltRune(str string) (rune, bool) { re := regexp.MustCompile(`\[(.)\]`) x := re.FindStringSubmatch(str) - return rune(x[0][1]) + if len(x) == 0 { + return rune(' '), false + } + return rune(x[0][1]), true } diff --git a/anko/anko_test.go b/anko/anko_test.go index ecddd323..978752dd 100644 --- a/anko/anko_test.go +++ b/anko/anko_test.go @@ -145,18 +145,22 @@ func TestExtractCtrlRune(t *testing.T) { tests := []struct { in string out rune + ok bool }{ - {in: "Ctrl+x", out: 'x'}, - {in: "Ctrl+]", out: ']'}, - {in: "Ctrl+%", out: '%'}, - {in: "Ctrl+^", out: '^'}, - {in: "Ctrl+7", out: '7'}, - {in: "Ctrl+B", out: 'B'}, + {in: "Ctrl+x", out: 'x', ok: true}, + {in: "Ctrl+]", out: ']', ok: true}, + {in: "Ctrl+%", out: '%', ok: true}, + {in: "Ctrl+^", out: '^', ok: true}, + {in: "Ctrl+7", out: '7', ok: true}, + {in: "Ctrl+B", out: 'B', ok: true}, + {in: "Ctrl+Down", out: ' ', ok: false}, + {in: "Ctrl+Left", out: ' ', ok: false}, } for _, test := range tests { - got := extractCtrlRune(test.in) + got, ok := extractCtrlRune(test.in) assert.Equal(t, test.out, got) + assert.Equal(t, test.ok, ok) } } @@ -164,18 +168,20 @@ func TestExtractAltRune(t *testing.T) { tests := []struct { in string out rune + ok bool }{ - {in: "Alt+Rune[x]", out: 'x'}, - {in: "Alt+Rune[]]", out: ']'}, - {in: "Alt+Rune[%]", out: '%'}, - {in: "Alt+Rune[^]", out: '^'}, - {in: "Alt+Rune[7]", out: '7'}, - {in: "Alt+Rune[B]", out: 'B'}, + {in: "Alt+Rune[x]", out: 'x', ok: true}, + {in: "Alt+Rune[]]", out: ']', ok: true}, + {in: "Alt+Rune[%]", out: '%', ok: true}, + {in: "Alt+Rune[^]", out: '^', ok: true}, + {in: "Alt+Rune[7]", out: '7', ok: true}, + {in: "Alt+Rune[B]", out: 'B', ok: true}, } for _, test := range tests { - got := extractAltRune(test.in) + got, ok := extractAltRune(test.in) assert.Equal(t, test.out, got) + assert.Equal(t, test.ok, ok) } }