@@ -5,10 +5,22 @@ import (
55 "strings"
66
77 tea "github.com/charmbracelet/bubbletea"
8+ "github.com/charmbracelet/lipgloss"
89)
910
1011const AllNonManagementText = "all non management accounts"
1112
13+ var (
14+ gray = lipgloss .Color ("240" )
15+ pink = lipgloss .Color ("205" )
16+
17+ helpStyle = lipgloss .NewStyle ().Foreground (gray )
18+ filterPlaceholderStyle = lipgloss .NewStyle ().Foreground (gray ).Faint (true )
19+ cursorStyle = lipgloss .NewStyle ().Foreground (pink )
20+
21+ helpTextMultipleChoice = "↑/↓/←/→: Navigate • Space: Select • Enter: Confirm"
22+ )
23+
1224type model struct {
1325 question string
1426 choices []string
@@ -18,6 +30,8 @@ type model struct {
1830 selected map [string ]struct {}
1931 allChoicesMap map [int ]string // Maps original index to choice text
2032 quit bool
33+ pageSize int
34+ currentPage int
2135}
2236
2337func (m model ) Init () tea.Cmd {
@@ -31,25 +45,43 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
3145 case "ctrl+c" :
3246 m .quit = true
3347 return m , tea .Quit
48+ case "enter" :
49+ if len (m .selected ) > 0 {
50+ return m , tea .Quit
51+ }
3452 case "up" :
3553 if m .cursor > 0 {
3654 m .cursor --
55+ } else if m .currentPage > 0 {
56+ m .currentPage --
57+ m .cursor = m .pageSize - 1
3758 }
3859 case "down" :
3960 if m .cursor < len (m .filtered )- 1 {
4061 m .cursor ++
62+ } else if (m .currentPage + 1 )* m .pageSize < len (m .filtered ) {
63+ m .currentPage ++
64+ m .cursor = 0
65+ }
66+ case "left" :
67+ if m .currentPage > 0 {
68+ m .currentPage --
69+ m .cursor = 0
70+ }
71+ case "right" :
72+ if (m .currentPage + 1 )* m .pageSize < len (m .filtered ) {
73+ m .currentPage ++
74+ m .cursor = 0
4175 }
4276 case " " :
4377 if len (m .filtered ) > 0 {
44- currentChoice := m .filtered [m .cursor ]
78+ currentChoice := m .filtered [m .currentPage * m . pageSize + m . cursor ]
4579 if _ , ok := m .selected [currentChoice ]; ok {
4680 delete (m .selected , currentChoice )
4781 } else {
4882 m .selected [currentChoice ] = struct {}{}
4983 }
5084 }
51- case "enter" :
52- return m , tea .Quit
5385 case "backspace" :
5486 if len (m .filter ) > 0 {
5587 m .filter = m .filter [:len (m .filter )- 1 ]
@@ -77,36 +109,59 @@ func (m *model) updateFilteredChoices() {
77109 }
78110 }
79111 }
80- if len (m .filtered ) == 0 {
81- m .cursor = 0
82- } else if m .cursor >= len (m .filtered ) {
83- m .cursor = len (m .filtered ) - 1
84- }
112+
113+ // Reset pagination when filter changes
114+ m .currentPage = 0
115+ m .cursor = 0
85116}
86117
87118func (m model ) View () string {
88- s := fmt .Sprintf ("%s: [Use arrows to move, space to select, enter to confirm, type to filter]\n \n " , m .question )
89- s += fmt .Sprintf ("Filter: %s\n \n " , m .filter )
119+ s := fmt .Sprintf ("%s:\n \n " , m .question )
120+
121+ filterText := "Filter: "
122+ if m .filter == "" {
123+ filterText += filterPlaceholderStyle .Render ("type to filter" )
124+ } else {
125+ filterText += m .filter
126+ }
127+ s += fmt .Sprintf ("%s\n \n " , helpStyle .Render (filterText ))
90128
91129 if len (m .filtered ) == 0 {
92130 s += "No matches found.\n "
93131 } else {
94- for i , choice := range m .filtered {
132+ start := m .currentPage * m .pageSize
133+ end := min (start + m .pageSize , len (m .filtered ))
134+
135+ for i , choice := range m .filtered [start :end ] {
95136 cursor := " "
96137 if m .cursor == i {
97- cursor = ">"
138+ cursor = cursorStyle . Render ( ">" )
98139 }
99140
100141 checked := " "
101142 if _ , ok := m .selected [choice ]; ok {
102- checked = "x"
143+ checked = cursorStyle . Render ( "x" )
103144 }
104145
105146 s += fmt .Sprintf ("%s [%s] %s\n " , cursor , checked , choice )
106147 }
148+
149+ if len (m .filtered ) > m .pageSize {
150+ s += fmt .Sprintf ("\n %s\n " ,
151+ helpStyle .Render (fmt .Sprintf ("Page %d/%d (Showing %d-%d of %d items)" ,
152+ m .currentPage + 1 ,
153+ (len (m .filtered )- 1 )/ m .pageSize + 1 ,
154+ start + 1 ,
155+ end ,
156+ len (m .filtered ))))
157+ }
158+ }
159+
160+ if len (m .selected ) == 0 {
161+ s += "\n " + helpStyle .Render ("Please select at least one item" )
107162 }
108163
109- s += "\n "
164+ s += "\n " + helpStyle . Render ( helpTextMultipleChoice )
110165
111166 return s
112167}
@@ -126,7 +181,9 @@ func Prompt(question string, choices []string) ([]int, error) {
126181 }
127182 return m
128183 }(),
129- quit : false ,
184+ quit : false ,
185+ pageSize : 10 ,
186+ currentPage : 0 ,
130187 }
131188
132189 p := tea .NewProgram (m )
0 commit comments