Skip to content

Commit

Permalink
Merge pull request #402 from jochil/customizable-multiselect-printer
Browse files Browse the repository at this point in the history
  • Loading branch information
MarvinJWendt committed Oct 1, 2022
2 parents 0da799e + 0250cff commit b14fbe3
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 20 deletions.
31 changes: 31 additions & 0 deletions _examples/interactive_multiselect/custom-keys/ci.go
@@ -0,0 +1,31 @@
package main

import (
"os"
"time"

"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
)

// ------ Automation for CI ------
// You can ignore this function, it is used to automatically run the demo and generate the example animation in our CI system.
func init() {
if os.Getenv("CI") == "true" {
go func() {
time.Sleep(time.Second)
keyboard.SimulateKeyPress(keys.Down)
time.Sleep(time.Millisecond * 100)
keyboard.SimulateKeyPress(keys.Space)

time.Sleep(time.Millisecond * 300)

keyboard.SimulateKeyPress(keys.Down)
time.Sleep(time.Millisecond * 100)
keyboard.SimulateKeyPress(keys.Space)

time.Sleep(time.Millisecond * 300)
keyboard.SimulateKeyPress(keys.Enter)
}()
}
}
23 changes: 23 additions & 0 deletions _examples/interactive_multiselect/custom-keys/main.go
@@ -0,0 +1,23 @@
package main

import (
"fmt"

"atomicgo.dev/keyboard/keys"
"github.com/pterm/pterm"
)

func main() {
var options []string

for i := 0; i < 5; i++ {
options = append(options, fmt.Sprintf("Option %d", i))
}

printer := pterm.DefaultInteractiveMultiselect.WithOptions(options)
printer.Filter = false
printer.KeyConfirm = keys.Enter
printer.KeySelect = keys.Space
selectedOptions, _ := printer.Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
77 changes: 57 additions & 20 deletions interactive_multiselect_printer.go
Expand Up @@ -22,6 +22,9 @@ var (
MaxHeight: 5,
Selector: ">",
SelectorStyle: &ThemeDefault.SecondaryStyle,
Filter: true,
KeySelect: keys.Enter,
KeyConfirm: keys.Tab,
}
)

Expand All @@ -35,6 +38,7 @@ type InteractiveMultiselectPrinter struct {
MaxHeight int
Selector string
SelectorStyle *Style
Filter bool

selectedOption int
selectedOptions []int
Expand All @@ -44,6 +48,9 @@ type InteractiveMultiselectPrinter struct {
displayedOptions []string
displayedOptionsStart int
displayedOptionsEnd int

KeySelect keys.KeyCode
KeyConfirm keys.KeyCode
}

// WithOptions sets the options.
Expand All @@ -70,6 +77,24 @@ func (p InteractiveMultiselectPrinter) WithMaxHeight(maxHeight int) *Interactive
return &p
}

// WithFilter sets the Filter option
func (p InteractiveMultiselectPrinter) WithFilter(filter bool) *InteractiveMultiselectPrinter {
p.Filter = filter
return &p
}

// WithKeySelect sets the confirm key
func (p InteractiveMultiselectPrinter) WithKeySelect(keySelect keys.KeyCode) *InteractiveMultiselectPrinter {
p.KeySelect = keySelect
return &p
}

// WithKeyConfirm sets the confirm key
func (p InteractiveMultiselectPrinter) WithKeyConfirm(keyConfirm keys.KeyCode) *InteractiveMultiselectPrinter {
p.KeyConfirm = keyConfirm
return &p
}

// Show shows the interactive multiselect menu and returns the selected entry.
func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
// should be the first defer statement to make sure it is executed last
Expand Down Expand Up @@ -111,6 +136,10 @@ func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
return nil, fmt.Errorf("could not start area: %w", err)
}

if p.Filter && (p.KeyConfirm == keys.Space || p.KeySelect == keys.Space) {
return nil, fmt.Errorf("if filter/search is active, keys.Space can not be used for KeySelect or KeyConfirm")
}

area.Update(p.renderSelectMenu())

cursor.Hide()
Expand All @@ -125,25 +154,35 @@ func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
}

switch key {
case keys.RuneKey:
// Fuzzy search for options
// append to fuzzy search string
p.fuzzySearchString += keyInfo.String()
p.selectedOption = 0
p.displayedOptionsStart = 0
p.displayedOptionsEnd = maxHeight
p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
area.Update(p.renderSelectMenu())
case keys.Tab:
case p.KeyConfirm:
if len(p.fuzzySearchMatches) == 0 {
return false, nil
}
area.Update(p.renderFinishedMenu())
return true, nil
case keys.Space:
p.fuzzySearchString += " "
p.selectedOption = 0
case p.KeySelect:
if len(p.fuzzySearchMatches) > 0 {
// Select option if not already selected
p.selectOption(p.fuzzySearchMatches[p.selectedOption])
}
area.Update(p.renderSelectMenu())
case keys.RuneKey:
if p.Filter {
// Fuzzy search for options
// append to fuzzy search string
p.fuzzySearchString += keyInfo.String()
p.selectedOption = 0
p.displayedOptionsStart = 0
p.displayedOptionsEnd = maxHeight
p.displayedOptions = append([]string{}, p.fuzzySearchMatches[:maxHeight]...)
}
area.Update(p.renderSelectMenu())
case keys.Space:
if p.Filter {
p.fuzzySearchString += " "
p.selectedOption = 0
area.Update(p.renderSelectMenu())
}
case keys.Backspace:
// Remove last character from fuzzy search string
if len(p.fuzzySearchString) > 0 {
Expand Down Expand Up @@ -226,12 +265,6 @@ func (p *InteractiveMultiselectPrinter) Show(text ...string) ([]string, error) {
case keys.CtrlC:
cancel()
return true, nil
case keys.Enter:
if len(p.fuzzySearchMatches) > 0 {
// Select option if not already selected
p.selectOption(p.fuzzySearchMatches[p.selectedOption])
}
area.Update(p.renderSelectMenu())
}

return false, nil
Expand Down Expand Up @@ -323,7 +356,11 @@ func (p *InteractiveMultiselectPrinter) renderSelectMenu() string {
}
}

content += ThemeDefault.SecondaryStyle.Sprintfln("enter: %s | tab: %s | left: %s | right: %s | type to %s", Bold.Sprint("select"), Bold.Sprint("confirm"), Bold.Sprint("none"), Bold.Sprint("all"), Bold.Sprint("filter"))
help := fmt.Sprintf("%s: %s | %s: %s | left: %s | right: %s", p.KeySelect, Bold.Sprint("select"), p.KeyConfirm, Bold.Sprint("confirm"), Bold.Sprint("none"), Bold.Sprint("all"))
if p.Filter {
help += fmt.Sprintf("| type to %s", Bold.Sprint("filter"))
}
content += ThemeDefault.SecondaryStyle.Sprintfln(help)

return content
}
Expand Down

0 comments on commit b14fbe3

Please sign in to comment.