Skip to content

Commit 2ddf970

Browse files
authored
feat(experiment): use chevron prompt for text inputs (#399)
1 parent defbe8f commit 2ddf970

File tree

7 files changed

+193
-176
lines changed

7 files changed

+193
-176
lines changed

internal/iostreams/charm.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
func buildInputForm(message string, cfg InputPromptConfig, input *string) *huh.Form {
3030
field := huh.NewInput().
3131
Title(message).
32+
Prompt(style.Chevron() + " ").
3233
Placeholder(cfg.Placeholder).
3334
Value(input)
3435
if cfg.Required {
@@ -106,6 +107,7 @@ func charmSelectPrompt(_ *IOStreams, _ context.Context, msg string, options []st
106107
func buildPasswordForm(message string, cfg PasswordPromptConfig, input *string) *huh.Form {
107108
field := huh.NewInput().
108109
Title(message).
110+
Prompt(style.Chevron() + " ").
109111
EchoMode(huh.EchoModePassword).
110112
Value(input)
111113
if cfg.Required {

internal/iostreams/charm_test.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
tea "charm.land/bubbletea/v2"
2222
huh "charm.land/huh/v2"
2323
"github.com/charmbracelet/x/ansi"
24+
"github.com/slackapi/slack-cli/internal/style"
2425
"github.com/stretchr/testify/assert"
2526
)
2627

@@ -39,6 +40,15 @@ func TestCharmInput(t *testing.T) {
3940
assert.Contains(t, view, "Enter your name")
4041
})
4142

43+
t.Run("renders the chevron prompt", func(t *testing.T) {
44+
var input string
45+
f := buildInputForm("Name?", InputPromptConfig{}, &input)
46+
f.Update(f.Init())
47+
48+
view := ansi.Strip(f.View())
49+
assert.Contains(t, view, style.Chevron())
50+
})
51+
4252
t.Run("accepts typed input", func(t *testing.T) {
4353
var input string
4454
f := buildInputForm("Name?", InputPromptConfig{}, &input)
@@ -136,7 +146,7 @@ func TestCharmSelect(t *testing.T) {
136146
f.Update(f.Init())
137147

138148
view := ansi.Strip(f.View())
139-
assert.Contains(t, view, "❱ Foo")
149+
assert.Contains(t, view, style.Chevron()+" Foo")
140150
})
141151

142152
t.Run("cursor navigation moves selection", func(t *testing.T) {
@@ -147,8 +157,8 @@ func TestCharmSelect(t *testing.T) {
147157

148158
m, _ := f.Update(tea.KeyPressMsg{Code: tea.KeyDown})
149159
view := ansi.Strip(m.View())
150-
assert.Contains(t, view, "❱ Bar")
151-
assert.False(t, strings.Contains(view, "❱ Foo"))
160+
assert.Contains(t, view, style.Chevron()+" Bar")
161+
assert.False(t, strings.Contains(view, style.Chevron()+" Foo"))
152162
})
153163

154164
t.Run("submit selects the hovered option", func(t *testing.T) {
@@ -207,6 +217,15 @@ func TestCharmPassword(t *testing.T) {
207217
assert.Contains(t, view, "Enter password")
208218
})
209219

220+
t.Run("renders the chevron prompt", func(t *testing.T) {
221+
var input string
222+
f := buildPasswordForm("Enter password", PasswordPromptConfig{}, &input)
223+
f.Update(f.Init())
224+
225+
view := ansi.Strip(f.View())
226+
assert.Contains(t, view, style.Chevron())
227+
})
228+
210229
t.Run("typed characters are masked in view", func(t *testing.T) {
211230
var input string
212231
f := buildPasswordForm("Password", PasswordPromptConfig{}, &input)
@@ -302,7 +321,7 @@ func TestCharmFormsUseSlackTheme(t *testing.T) {
302321
f.Update(f.Init())
303322

304323
view := ansi.Strip(f.View())
305-
assert.Contains(t, view, "❱ A")
324+
assert.Contains(t, view, style.Chevron()+" A")
306325
})
307326

308327
t.Run("multi-select form renders themed prefixes", func(t *testing.T) {

internal/style/charm_theme_test.go

Lines changed: 0 additions & 118 deletions
This file was deleted.

internal/style/format.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ import (
2323
"runtime"
2424
"strings"
2525
"time"
26-
27-
"github.com/AlecAivazis/survey/v2"
28-
"github.com/AlecAivazis/survey/v2/core"
2926
)
3027

3128
const LocalRunNameTag = "(local)"
@@ -184,30 +181,6 @@ func HomePath(filepath string) string {
184181
return filepath
185182
}
186183

187-
// SurveyIcons returns customizations to the appearance of prompts
188-
func SurveyIcons() survey.AskOpt {
189-
if !isStyleEnabled {
190-
core.DisableColor = true
191-
}
192-
193-
cursor := ">"
194-
// Unfortunately "❱" does not display on Windows Powershell
195-
// Limit "❱" to macOS until support is known for other operating systems
196-
if isStyleEnabled && runtime.GOOS == "darwin" {
197-
cursor = "❱"
198-
}
199-
200-
// Customize the appearance of each survey prompt
201-
return survey.WithIcons(func(icons *survey.IconSet) {
202-
icons.SelectFocus.Text = cursor
203-
icons.SelectFocus.Format = fmt.Sprintf("%d+b", blue)
204-
icons.MarkedOption.Format = fmt.Sprintf("%d+b", blue)
205-
206-
icons.Question.Text = "?"
207-
icons.Question.Format = fmt.Sprintf("%d+hb", gray)
208-
})
209-
}
210-
211184
// ExampleCommand contains a command with a descriptive meaning
212185
type ExampleCommand struct {
213186
// Command is the command to be run, not including the process name

internal/style/format_test.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"strings"
2121
"testing"
2222

23-
"github.com/AlecAivazis/survey/v2/core"
2423
"github.com/stretchr/testify/assert"
2524
)
2625

@@ -199,29 +198,6 @@ func TestTracef(t *testing.T) {
199198
}
200199
}
201200

202-
func TestSurveyIcons(t *testing.T) {
203-
tests := map[string]struct {
204-
styleEnabled bool
205-
}{
206-
"styles are not enabled": {
207-
styleEnabled: false,
208-
},
209-
"styles are enabled": {
210-
styleEnabled: true,
211-
},
212-
}
213-
214-
for name, tc := range tests {
215-
t.Run(name, func(t *testing.T) {
216-
core.DisableColor = false
217-
isStyleEnabled = tc.styleEnabled
218-
219-
_ = SurveyIcons()
220-
assert.NotEqual(t, tc.styleEnabled, core.DisableColor)
221-
})
222-
}
223-
}
224-
225201
/*
226202
* Example commands
227203
*/
Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@
1414

1515
package style
1616

17-
// Slack brand theme for charmbracelet/huh prompts.
17+
// Slack brand theme for prompt styling.
1818
// Uses official Slack brand colors defined in colors.go.
1919

2020
import (
21+
"fmt"
22+
"runtime"
23+
2124
huh "charm.land/huh/v2"
2225
lipgloss "charm.land/lipgloss/v2"
26+
27+
"github.com/AlecAivazis/survey/v2"
28+
"github.com/AlecAivazis/survey/v2/core"
2329
)
2430

2531
// ThemeSlack returns a huh Theme styled with Slack brand colors.
@@ -49,7 +55,7 @@ func themeSlack(isDark bool) *huh.Styles {
4955
// Select styles
5056
t.Focused.SelectSelector = lipgloss.NewStyle().
5157
Foreground(slackBlue).
52-
SetString("❱ ")
58+
SetString(Chevron() + " ")
5359
t.Focused.Option = lipgloss.NewStyle().
5460
Foreground(slackOptionText)
5561
t.Focused.NextIndicator = lipgloss.NewStyle().
@@ -64,7 +70,7 @@ func themeSlack(isDark bool) *huh.Styles {
6470
// Multi-select styles
6571
t.Focused.MultiSelectSelector = lipgloss.NewStyle().
6672
Foreground(slackYellow).
67-
SetString("❱ ")
73+
SetString(Chevron() + " ")
6874
t.Focused.SelectedOption = lipgloss.NewStyle().
6975
Foreground(slackGreen)
7076
t.Focused.SelectedPrefix = lipgloss.NewStyle().
@@ -109,3 +115,31 @@ func themeSlack(isDark bool) *huh.Styles {
109115

110116
return t
111117
}
118+
119+
// Chevron returns the select chevron character for the current platform.
120+
// Unfortunately "❱" does not display on Windows Powershell.
121+
// Limit "❱" to non-Windows until support is known for other operating systems.
122+
func Chevron() string {
123+
if !isStyleEnabled || runtime.GOOS == "windows" {
124+
return ">"
125+
}
126+
return "❱"
127+
}
128+
129+
// SurveyIcons returns customizations to the appearance of survey prompts.
130+
func SurveyIcons() survey.AskOpt {
131+
if !isStyleEnabled {
132+
core.DisableColor = true
133+
}
134+
135+
cursor := Chevron()
136+
137+
return survey.WithIcons(func(icons *survey.IconSet) {
138+
icons.SelectFocus.Text = cursor
139+
icons.SelectFocus.Format = fmt.Sprintf("%d+b", blue)
140+
icons.MarkedOption.Format = fmt.Sprintf("%d+b", blue)
141+
142+
icons.Question.Text = "?"
143+
icons.Question.Format = fmt.Sprintf("%d+hb", gray)
144+
})
145+
}

0 commit comments

Comments
 (0)