@@ -6,15 +6,18 @@ import (
6
6
7
7
"github.com/charmbracelet/bubbles/table"
8
8
"github.com/charmbracelet/bubbles/textinput"
9
+ "github.com/charmbracelet/bubbles/viewport"
9
10
tea "github.com/charmbracelet/bubbletea"
10
11
"github.com/charmbracelet/lipgloss"
11
12
)
12
13
13
14
type preWizardModel struct {
14
- table table.Model
15
- textInput textinput.Model
16
- msgChan chan GitProvider
17
- err error
15
+ windowIsReady bool
16
+ viewport viewport.Model
17
+ table table.Model
18
+ textInput textinput.Model
19
+ msgChan chan GitProvider
20
+ err error
18
21
}
19
22
20
23
const flagSeparator = " - "
26
29
BorderStyle (lipgloss .NormalBorder ()).
27
30
BorderForeground (lipgloss .Color ("240" ))
28
31
29
- // text inputs style
32
+ // text inputs
30
33
focusedStyle = lipgloss .NewStyle ().Foreground (lipgloss .Color ("205" ))
31
34
blurredStyle = lipgloss .NewStyle ().Foreground (lipgloss .Color ("240" ))
32
35
39
42
blurredButton = fmt .Sprintf ("[ %s ]" , blurredStyle .Render ("Submit" ))
40
43
)
41
44
45
+ func makeViewport (width int , height int , content string ) viewport.Model {
46
+ vp := viewport .New (width , height )
47
+ vp .YPosition = 0
48
+ vp .SetContent (content )
49
+
50
+ return vp
51
+ }
52
+
42
53
func initialPreWizardModel (msgChan chan GitProvider ) preWizardModel {
43
54
columns := []table.Column {
44
55
{Title : "Index" , Width : 6 },
@@ -65,10 +76,7 @@ func initialPreWizardModel(msgChan chan GitProvider) preWizardModel {
65
76
BorderForeground (lipgloss .Color ("240" )).
66
77
BorderBottom (true ).
67
78
Bold (false )
68
- s .Selected = s .Selected .
69
- Foreground (lipgloss .Color ("229" )).
70
- Background (lipgloss .Color ("57" )).
71
- Bold (false )
79
+ s .Selected = s .Selected .Bold (false ).Foreground (lipgloss.NoColor {})
72
80
t .SetStyles (s )
73
81
74
82
ti := textinput .New ()
@@ -94,30 +102,17 @@ func (m preWizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
94
102
switch msg .Type {
95
103
case tea .KeyCtrlC :
96
104
return m , tea .Quit
97
- case tea .KeyEscape , tea .KeyTab :
98
- if m .table .Focused () {
99
- m .table .Blur ()
100
- m .textInput .Focus ()
101
- } else {
102
- m .table .Focus ()
103
- m .textInput .Blur ()
104
- }
105
105
case tea .KeyEnter :
106
106
provider := GitProviderUnknown
107
107
108
- if m .table .Focused () {
109
- name := m .table .SelectedRow ()[1 ]
110
- provider = allGitProviders [name ]
111
- } else {
112
- indexOrName := strings .ToLower (strings .TrimSpace (m .textInput .Value ()))
108
+ indexOrName := strings .ToLower (strings .TrimSpace (m .textInput .Value ()))
113
109
114
- for key , value := range allGitProviders {
115
- strValue := fmt .Sprint (value )
110
+ for key , value := range allGitProviders {
111
+ strValue := fmt .Sprint (value )
116
112
117
- if indexOrName == strings .ToLower (strValue ) || indexOrName == strings .ToLower (key ) {
118
- provider = allGitProviders [key ]
119
- break
120
- }
113
+ if indexOrName == strings .ToLower (strValue ) || indexOrName == strings .ToLower (key ) {
114
+ provider = allGitProviders [key ]
115
+ break
121
116
}
122
117
}
123
118
@@ -127,42 +122,59 @@ func (m preWizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
127
122
return m , tea .Quit
128
123
}
129
124
}
125
+ case tea.WindowSizeMsg :
126
+ if ! m .windowIsReady {
127
+ m .viewport = makeViewport (msg .Width , msg .Height , m .getContent ())
128
+
129
+ m .windowIsReady = true
130
+ } else {
131
+ m .viewport .Width = msg .Width
132
+ m .viewport .Height = msg .Height
133
+ }
130
134
case errMsg :
131
135
m .err = msg
132
136
return m , nil
133
137
}
134
138
135
139
var (
140
+ cmdViewport tea.Cmd
136
141
cmdTable tea.Cmd
137
142
cmdTextInput tea.Cmd
138
143
)
139
144
140
145
m .table , cmdTable = m .table .Update (msg )
141
146
m .textInput , cmdTextInput = m .textInput .Update (msg )
142
147
143
- return m , tea .Batch ([]tea.Cmd {cmdTable , cmdTextInput }... )
148
+ m .viewport .SetContent (m .getContent ())
149
+
150
+ m .viewport , cmdViewport = m .viewport .Update (msg )
151
+ cmds := []tea.Cmd {cmdViewport , cmdTable , cmdTextInput }
152
+
153
+ return m , tea .Batch (cmds ... )
144
154
}
145
155
146
156
func (m preWizardModel ) View () string {
157
+ return m .viewport .View ()
158
+ }
159
+
160
+ func (m preWizardModel ) getContent () string {
147
161
return fmt .Sprintf (
148
- "Please select or enter your Git provider" + "\n " +
149
- "(up and down arrows to move table selection, Enter to select git provider, " + "\n " +
150
- "Esc to switch between table and text input, Ctrl + C twice to quit)" + "\n " +
151
- "\n %s" ,
162
+ "Please enter Git provider index or name and press Enter" + "\n " +
163
+ "(up and down arrows to scroll the view," + "\n " +
164
+ "Ctrl+C twice to quit):" + "\n %s" ,
152
165
baseTableStyle .Render (m .table .View ())+ "\n " ,
153
- ) + fmt .Sprintf (
154
- "Please enter Git provider index or name and press Enter\n %s" ,
155
- m .textInput .View (),
156
- )
166
+ ) + m .textInput .View ()
157
167
}
158
168
159
169
type wizardModel struct {
160
- textInputs []textinput.Model
161
- prompts []string
162
- msgChan chan BootstrapCmdOptions
163
- cursorMode textinput.CursorMode
164
- focusIndex int
165
- errorMsg string
170
+ windowIsReady bool
171
+ viewport viewport.Model
172
+ textInputs []textinput.Model
173
+ prompts []string
174
+ msgChan chan BootstrapCmdOptions
175
+ cursorMode textinput.CursorMode
176
+ focusIndex int
177
+ errorMsg string
166
178
}
167
179
168
180
func makeTextInput (task * BootstrapWizardTask , isFocused bool ) textinput.Model {
@@ -218,6 +230,8 @@ func (m wizardModel) Init() tea.Cmd {
218
230
}
219
231
220
232
func (m wizardModel ) Update (msg tea.Msg ) (tea.Model , tea.Cmd ) {
233
+ var cmds []tea.Cmd
234
+
221
235
switch msg := msg .(type ) {
222
236
case tea.KeyMsg :
223
237
switch msg .Type {
@@ -231,20 +245,16 @@ func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
231
245
m .cursorMode = textinput .CursorBlink
232
246
}
233
247
234
- cmds := make ([]tea.Cmd , len (m .textInputs ))
248
+ cmdsTextInputs := make ([]tea.Cmd , len (m .textInputs ))
235
249
236
250
for i := range m .textInputs {
237
- cmds [i ] = m .textInputs [i ].SetCursorMode (m .cursorMode )
251
+ cmdsTextInputs [i ] = m .textInputs [i ].SetCursorMode (m .cursorMode )
238
252
}
239
253
240
- return m , tea .Batch (cmds ... )
241
-
242
- // Set focus to next input
243
- case tea .KeyTab , tea .KeyShiftTab , tea .KeyEnter , tea .KeyUp , tea .KeyDown :
254
+ cmds = append (cmds , cmdsTextInputs ... )
255
+ case tea .KeyTab , tea .KeyShiftTab , tea .KeyEnter :
244
256
t := msg .Type
245
257
246
- // Did the user press enter while the submit button was focused?
247
- // If so, exit.
248
258
if t == tea .KeyEnter && m .focusIndex == len (m .textInputs ) {
249
259
options := make (BootstrapCmdOptions )
250
260
@@ -266,8 +276,7 @@ func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
266
276
return m , tea .Quit
267
277
}
268
278
269
- // Cycle indexes
270
- if t == tea .KeyUp || t == tea .KeyShiftTab {
279
+ if t == tea .KeyShiftTab {
271
280
m .focusIndex --
272
281
} else {
273
282
m .focusIndex ++
@@ -279,31 +288,50 @@ func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
279
288
m .focusIndex = len (m .textInputs )
280
289
}
281
290
282
- cmds := make ([]tea.Cmd , len (m .textInputs ))
291
+ cmdsTextInputs := make ([]tea.Cmd , len (m .textInputs ))
283
292
284
293
for i := 0 ; i <= len (m .textInputs )- 1 ; i ++ {
285
294
if i == m .focusIndex {
286
- // Set focused state
287
- cmds [i ] = m .textInputs [i ].Focus ()
295
+ cmdsTextInputs [i ] = m .textInputs [i ].Focus ()
288
296
m .textInputs [i ].PromptStyle = focusedStyle
289
297
m .textInputs [i ].TextStyle = focusedStyle
290
298
291
299
continue
292
300
}
293
- // Remove focused state
301
+
294
302
m .textInputs [i ].Blur ()
295
303
m .textInputs [i ].PromptStyle = noStyle
296
304
m .textInputs [i ].TextStyle = noStyle
297
305
}
298
306
299
- return m , tea .Batch (cmds ... )
307
+ cmds = append (cmds , cmdsTextInputs ... )
308
+ }
309
+ case tea.WindowSizeMsg :
310
+ if ! m .windowIsReady {
311
+ m .viewport = makeViewport (msg .Width , msg .Height , m .getContent ())
312
+
313
+ m .windowIsReady = true
314
+ } else {
315
+ m .viewport .Width = msg .Width
316
+ m .viewport .Height = msg .Height
300
317
}
301
318
}
302
319
303
- // Handle character input and blinking
304
- cmd := m .updateInputs (msg )
320
+ cmdsTextInputs := m .updateInputs (msg )
321
+
322
+ m .viewport .SetContent (m .getContent ())
323
+
324
+ var cmdViewport tea.Cmd
305
325
306
- return m , cmd
326
+ m .viewport , cmdViewport = m .viewport .Update (msg )
327
+
328
+ cmds = append (cmds , cmdsTextInputs , cmdViewport )
329
+
330
+ return m , tea .Batch (cmds ... )
331
+ }
332
+
333
+ func (m wizardModel ) View () string {
334
+ return m .viewport .View ()
307
335
}
308
336
309
337
func (m * wizardModel ) updateInputs (msg tea.Msg ) tea.Cmd {
@@ -318,13 +346,13 @@ func (m *wizardModel) updateInputs(msg tea.Msg) tea.Cmd {
318
346
return tea .Batch (cmds ... )
319
347
}
320
348
321
- func (m wizardModel ) View () string {
349
+ func (m wizardModel ) getContent () string {
322
350
var b strings.Builder
323
351
324
352
b .WriteString ("Please enter the following values" + "\n " +
325
353
"(Tab and Shift+Tab to move input selection," + "\n " +
326
354
"Enter to move to the next input or submit the form, " + "\n " +
327
- "Ctrl + C twice to quit)" + "\n \n \n " )
355
+ "up and down arrows to scroll the view, Ctrl+ C twice to quit): " + "\n \n \n " )
328
356
329
357
for i := range m .textInputs {
330
358
b .WriteString (m .prompts [i ])
0 commit comments