From 38664930d07869ba579fce6d8aaa23561427bef4 Mon Sep 17 00:00:00 2001 From: eli n chokeir Date: Wed, 22 Jul 2026 15:39:43 -0700 Subject: [PATCH] fix: cursor between boundaries crash when the mentions.go does the check to see if there is a username after an "@", the cursors loc was able to get out of bounds, causing a runtime error. now userStart is able to be the same value as len(runes). fixes #939 --- .../tui/components/fuzzyselect/mentions.go | 2 +- .../tui/components/fuzzyselect/source_test.go | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/internal/tui/components/fuzzyselect/mentions.go b/internal/tui/components/fuzzyselect/mentions.go index dbd3a4219..51f42b918 100644 --- a/internal/tui/components/fuzzyselect/mentions.go +++ b/internal/tui/components/fuzzyselect/mentions.go @@ -49,7 +49,7 @@ func (src *UserMentionSource) ExtractContext(input string, cursorPos tea.Positio } if userStart >= len(runes)+1 || - (userStart > 0 && userStart < len(runes) && src.WithAtSymbol && runes[userStart-1] != '@') { + (userStart > 0 && userStart <= len(runes) && src.WithAtSymbol && runes[userStart-1] != '@') { return Context{} } diff --git a/internal/tui/components/fuzzyselect/source_test.go b/internal/tui/components/fuzzyselect/source_test.go index ab764ca18..d01da8c29 100644 --- a/internal/tui/components/fuzzyselect/source_test.go +++ b/internal/tui/components/fuzzyselect/source_test.go @@ -238,6 +238,41 @@ func TestUserMentionSource(t *testing.T) { require.Equal(t, tea.Position{X: 12}, newCursor) } +func TestUserMentionSourceCursorBetweenBoundaries(t *testing.T) { + testCases := []struct { + name string + input string + cursorPos tea.Position + }{ + { + name: "cursor between two trailing spaces", + input: "hello ", + cursorPos: tea.Position{X: 6}, + }, + { + name: "cursor before the only char, which is a boundary", + input: " ", + cursorPos: tea.Position{X: 0}, + }, + { + name: "cursor between a space and a trailing punctuation mark", + input: "hello @octo .", + cursorPos: tea.Position{X: 12}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + for _, withAt := range []bool{true, false} { + source := UserMentionSource{WithAtSymbol: withAt} + require.NotPanics(t, func() { + source.ExtractContext(tc.input, tc.cursorPos) + }) + } + }) + } +} + func TestUserMentionSourceWithoutAtSymbol(t *testing.T) { source := UserMentionSource{WithAtSymbol: false} require.Equal(