Skip to content

Commit e5b4428

Browse files
committed
Wrap bootstrap wizard UI elements with a viewport component.
Rework bootstrap wizard message handling. Remove unneeded comments. Run `npm audit fix`.
1 parent a9e0cf9 commit e5b4428

File tree

3 files changed

+99
-71
lines changed

3 files changed

+99
-71
lines changed

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/run/bootstrap/bootstrap_wizard.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ func SelectGitProvider(log logger.Logger) (GitProvider, error) {
476476

477477
m := initialPreWizardModel(make(chan GitProvider))
478478

479-
err := tea.NewProgram(m).Start()
479+
err := tea.NewProgram(m, tea.WithAltScreen(), tea.WithMouseCellMotion()).Start()
480480
if err != nil {
481481
return provider, fmt.Errorf("could not start tea program: %v", err.Error())
482482
}
@@ -492,7 +492,7 @@ func (wizard *BootstrapWizard) Run(log logger.Logger) error {
492492

493493
m := initialWizardModel(wizard.tasks, make(chan BootstrapCmdOptions))
494494

495-
err := tea.NewProgram(m).Start()
495+
err := tea.NewProgram(m, tea.WithAltScreen(), tea.WithMouseCellMotion()).Start()
496496
if err != nil {
497497
return fmt.Errorf("could not start tea program: %v", err.Error())
498498
}

pkg/run/bootstrap/bootstrap_wizard_ui.go

Lines changed: 91 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import (
66

77
"github.com/charmbracelet/bubbles/table"
88
"github.com/charmbracelet/bubbles/textinput"
9+
"github.com/charmbracelet/bubbles/viewport"
910
tea "github.com/charmbracelet/bubbletea"
1011
"github.com/charmbracelet/lipgloss"
1112
)
1213

1314
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
1821
}
1922

2023
const flagSeparator = " - "
@@ -26,7 +29,7 @@ var (
2629
BorderStyle(lipgloss.NormalBorder()).
2730
BorderForeground(lipgloss.Color("240"))
2831

29-
// text inputs style
32+
// text inputs
3033
focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
3134
blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
3235

@@ -39,6 +42,14 @@ var (
3942
blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit"))
4043
)
4144

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+
4253
func initialPreWizardModel(msgChan chan GitProvider) preWizardModel {
4354
columns := []table.Column{
4455
{Title: "Index", Width: 6},
@@ -65,10 +76,7 @@ func initialPreWizardModel(msgChan chan GitProvider) preWizardModel {
6576
BorderForeground(lipgloss.Color("240")).
6677
BorderBottom(true).
6778
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{})
7280
t.SetStyles(s)
7381

7482
ti := textinput.New()
@@ -94,30 +102,17 @@ func (m preWizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
94102
switch msg.Type {
95103
case tea.KeyCtrlC:
96104
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-
}
105105
case tea.KeyEnter:
106106
provider := GitProviderUnknown
107107

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()))
113109

114-
for key, value := range allGitProviders {
115-
strValue := fmt.Sprint(value)
110+
for key, value := range allGitProviders {
111+
strValue := fmt.Sprint(value)
116112

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
121116
}
122117
}
123118

@@ -127,42 +122,59 @@ func (m preWizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
127122
return m, tea.Quit
128123
}
129124
}
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+
}
130134
case errMsg:
131135
m.err = msg
132136
return m, nil
133137
}
134138

135139
var (
140+
cmdViewport tea.Cmd
136141
cmdTable tea.Cmd
137142
cmdTextInput tea.Cmd
138143
)
139144

140145
m.table, cmdTable = m.table.Update(msg)
141146
m.textInput, cmdTextInput = m.textInput.Update(msg)
142147

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...)
144154
}
145155

146156
func (m preWizardModel) View() string {
157+
return m.viewport.View()
158+
}
159+
160+
func (m preWizardModel) getContent() string {
147161
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",
152165
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()
157167
}
158168

159169
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
166178
}
167179

168180
func makeTextInput(task *BootstrapWizardTask, isFocused bool) textinput.Model {
@@ -218,6 +230,8 @@ func (m wizardModel) Init() tea.Cmd {
218230
}
219231

220232
func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
233+
var cmds []tea.Cmd
234+
221235
switch msg := msg.(type) {
222236
case tea.KeyMsg:
223237
switch msg.Type {
@@ -231,20 +245,16 @@ func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
231245
m.cursorMode = textinput.CursorBlink
232246
}
233247

234-
cmds := make([]tea.Cmd, len(m.textInputs))
248+
cmdsTextInputs := make([]tea.Cmd, len(m.textInputs))
235249

236250
for i := range m.textInputs {
237-
cmds[i] = m.textInputs[i].SetCursorMode(m.cursorMode)
251+
cmdsTextInputs[i] = m.textInputs[i].SetCursorMode(m.cursorMode)
238252
}
239253

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:
244256
t := msg.Type
245257

246-
// Did the user press enter while the submit button was focused?
247-
// If so, exit.
248258
if t == tea.KeyEnter && m.focusIndex == len(m.textInputs) {
249259
options := make(BootstrapCmdOptions)
250260

@@ -266,8 +276,7 @@ func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
266276
return m, tea.Quit
267277
}
268278

269-
// Cycle indexes
270-
if t == tea.KeyUp || t == tea.KeyShiftTab {
279+
if t == tea.KeyShiftTab {
271280
m.focusIndex--
272281
} else {
273282
m.focusIndex++
@@ -279,31 +288,50 @@ func (m wizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
279288
m.focusIndex = len(m.textInputs)
280289
}
281290

282-
cmds := make([]tea.Cmd, len(m.textInputs))
291+
cmdsTextInputs := make([]tea.Cmd, len(m.textInputs))
283292

284293
for i := 0; i <= len(m.textInputs)-1; i++ {
285294
if i == m.focusIndex {
286-
// Set focused state
287-
cmds[i] = m.textInputs[i].Focus()
295+
cmdsTextInputs[i] = m.textInputs[i].Focus()
288296
m.textInputs[i].PromptStyle = focusedStyle
289297
m.textInputs[i].TextStyle = focusedStyle
290298

291299
continue
292300
}
293-
// Remove focused state
301+
294302
m.textInputs[i].Blur()
295303
m.textInputs[i].PromptStyle = noStyle
296304
m.textInputs[i].TextStyle = noStyle
297305
}
298306

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
300317
}
301318
}
302319

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
305325

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()
307335
}
308336

309337
func (m *wizardModel) updateInputs(msg tea.Msg) tea.Cmd {
@@ -318,13 +346,13 @@ func (m *wizardModel) updateInputs(msg tea.Msg) tea.Cmd {
318346
return tea.Batch(cmds...)
319347
}
320348

321-
func (m wizardModel) View() string {
349+
func (m wizardModel) getContent() string {
322350
var b strings.Builder
323351

324352
b.WriteString("Please enter the following values" + "\n" +
325353
"(Tab and Shift+Tab to move input selection," + "\n" +
326354
"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")
328356

329357
for i := range m.textInputs {
330358
b.WriteString(m.prompts[i])

0 commit comments

Comments
 (0)