Skip to content

chore: replace AlecAivazis/survey with charmbracelet/bubbletea #14475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Sep 4, 2024
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3934cb6
chore: replace survery library with bubbletea
DanielleMaywood Aug 29, 2024
164402b
chore: fix nolint comments
DanielleMaywood Aug 29, 2024
360fb95
chore: add message and colour to select prompts
DanielleMaywood Aug 29, 2024
7cf35d1
chore: make SelectedOptions private
DanielleMaywood Aug 29, 2024
b5092a6
chore: add filtering for multiselect, improve filtering algo
DanielleMaywood Aug 29, 2024
e4c010e
chore: allow vertical wrap on select/multiselect
DanielleMaywood Aug 29, 2024
2b6cd6e
chore: fix failing jobs
DanielleMaywood Aug 29, 2024
35fe461
chore: update charmbracelet/bubbletea to v1.0.0
DanielleMaywood Aug 29, 2024
5982185
chore: remove windows testing workaround for survey library
DanielleMaywood Aug 29, 2024
affbfbe
chore: update bubbletea to v1.1.0
DanielleMaywood Sep 2, 2024
33196cd
chore: reimplement testing workaround
DanielleMaywood Sep 2, 2024
409cec5
chore: use survey's default page size
DanielleMaywood Sep 2, 2024
52ed127
chore: ensure no underflow on page bottom
DanielleMaywood Sep 2, 2024
60c83d0
chore: remove multi-select test from cmd/cliui
DanielleMaywood Sep 3, 2024
2b621ce
chore: disable HideSearch from cmd/cliui select
DanielleMaywood Sep 3, 2024
8a3cd26
chore: use strings.Builder, fix select all logic, apply nitpicks
DanielleMaywood Sep 3, 2024
6e59ecb
chore: use strings.Builder
DanielleMaywood Sep 3, 2024
579c73b
chore: move m.search.Update out of case
DanielleMaywood Sep 3, 2024
9078242
chore: use tea.WithContext(inv.Context()) for tea program
DanielleMaywood Sep 3, 2024
f2ed4fa
chore: return nil as err already handled
DanielleMaywood Sep 3, 2024
7784110
chore: use const instead of magic number
DanielleMaywood Sep 3, 2024
f598836
chore: handle signals ourself instead of bubbletea
DanielleMaywood Sep 3, 2024
8a7f1bc
chore: update flake.nix
DanielleMaywood Sep 4, 2024
77804e0
chore: update flake.nix
DanielleMaywood Sep 4, 2024
2904b7c
chore: update flake.nix
DanielleMaywood Sep 4, 2024
0b99afe
chore: update flake.nix
DanielleMaywood Sep 4, 2024
b173fb0
chore: update flake.nix
DanielleMaywood Sep 4, 2024
966f772
chore: update flake.nix
DanielleMaywood Sep 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: add filtering for multiselect, improve filtering algo
  • Loading branch information
DanielleMaywood committed Sep 4, 2024
commit b5092a638bd73c8624f88d6d90bbe145c5eacfda
72 changes: 49 additions & 23 deletions cli/cliui/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,10 @@ func (m selectModel) viewableOptions() ([]string, int) {
func (m selectModel) filteredOptions() []string {
options := []string{}
for _, o := range m.options {
prefix := strings.ToLower(m.search.Value())
filter := strings.ToLower(m.search.Value())
option := strings.ToLower(o)

if strings.HasPrefix(option, prefix) {
if strings.Contains(option, filter) {
options = append(options, o)
}
}
Expand All @@ -249,15 +249,20 @@ func MultiSelect(inv *serpent.Invocation, opts MultiSelectOptions) ([]string, er
return opts.Defaults, nil
}

options := make([]multiSelectOption, len(opts.Options))
options := make([]*multiSelectOption, len(opts.Options))
for i, option := range opts.Options {
options[i].option = option

chosen := false
for _, d := range opts.Defaults {
if option == d {
options[i].chosen = true
chosen = true
}
}

options[i] = &multiSelectOption{
option: option,
chosen: chosen,
}

}

initialModel := multiSelectModel{
Expand Down Expand Up @@ -293,7 +298,7 @@ type multiSelectOption struct {

type multiSelectModel struct {
search textinput.Model
options []multiSelectOption
options []*multiSelectOption
cursor int
message string
canceled bool
Expand Down Expand Up @@ -321,8 +326,9 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case tea.KeySpace:
if len(m.options) != 0 {
m.options[m.cursor].chosen = !m.options[m.cursor].chosen
options := m.filteredOptions()
if len(options) != 0 {
options[m.cursor].chosen = !options[m.cursor].chosen
}

case tea.KeyUp:
Expand All @@ -336,13 +342,15 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case tea.KeyRight:
for i := range m.options {
m.options[i].chosen = true
options := m.filteredOptions()
for _, option := range options {
option.chosen = false
}

case tea.KeyLeft:
for i := range m.options {
m.options[i].chosen = false
options := m.filteredOptions()
for _, option := range options {
option.chosen = false
}

default:
Expand All @@ -352,8 +360,9 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// If the search query has changed then we need to ensure
// the cursor is still pointing at a valid option.
if m.search.Value() != oldSearch {
if m.cursor > len(m.options)-1 {
m.cursor = max(0, len(m.options)-1)
options := m.filteredOptions()
if m.cursor > len(options)-1 {
m.cursor = max(0, len(options)-1)
}
}
}
Expand All @@ -370,23 +379,27 @@ func (m multiSelectModel) View() string {
if !m.selected {
s += fmt.Sprintf("%s %s[Use arrows to move, space to select, <right> to all, <left> to none, type to filter]\n", msg, m.search.View())

for i, option := range m.options {
for i, option := range m.filteredOptions() {
cursor := " "
chosen := "[ ]"
o := option.option

if m.cursor == i {
cursor = pretty.Sprint(pretty.FgColor(Green), "> ")
chosen = pretty.Sprint(pretty.FgColor(Green), "[ ]")
o = pretty.Sprint(pretty.FgColor(Green), o)
}

chosen := "[ ]"
if option.chosen {
chosen = pretty.Sprint(pretty.FgColor(Green), "[x]")
}

o := option.option
if m.cursor == i {
o = pretty.Sprint(pretty.FgColor(Green), o)
}

s += fmt.Sprintf("%s%s %s\n", cursor, chosen, o)
s += fmt.Sprintf(
"%s%s %s\n",
cursor,
chosen,
o,
)
}
} else {
selected := pretty.Sprint(DefaultStyles.Keyword, strings.Join(m.selectedOptions(), ", "))
Expand All @@ -397,6 +410,19 @@ func (m multiSelectModel) View() string {
return s
}

func (m multiSelectModel) filteredOptions() []*multiSelectOption {
options := []*multiSelectOption{}
for _, o := range m.options {
filter := strings.ToLower(m.search.Value())
option := strings.ToLower(o.option)

if strings.Contains(option, filter) {
options = append(options, o)
}
}
return options
}

func (m multiSelectModel) selectedOptions() []string {
selected := []string{}
for _, o := range m.options {
Expand Down