Skip to content

Commit

Permalink
Merge pull request #429 from KarolosLykos/issue-418-proposal_option_t…
Browse files Browse the repository at this point in the history
…o_change_checkmarks_in_interactice_multiselect

Fixes #418
  • Loading branch information
MarvinJWendt committed Jan 5, 2023
2 parents c1e924e + 2806031 commit 19c2c06
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 2 deletions.
38 changes: 38 additions & 0 deletions README.md
Expand Up @@ -1091,6 +1091,44 @@ func main() {

</details>

### interactive_multiselect/custom-checkmarks

![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-checkmarks/animation.svg)

<details>

<summary>SHOW SOURCE</summary>

```go
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
printer.Checkmark = pterm.Checkmark{Checked: "+", Unchecked: "-"}
selectedOptions, _ := printer.Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}

```

</details>

### interactive_multiselect/custom-keys

![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-keys/animation.svg)
Expand Down
38 changes: 38 additions & 0 deletions _examples/interactive_multiselect/README.md
@@ -1,3 +1,41 @@
### interactive_multiselect/custom-checkmarks

![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-checkmarks/animation.svg)

<details>

<summary>SHOW SOURCE</summary>

```go
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
printer.Checkmark = pterm.Checkmark{Checked: "+", Unchecked: "-"}
selectedOptions, _ := printer.Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}

```

</details>

### interactive_multiselect/custom-keys

![Animation](https://raw.githubusercontent.com/pterm/pterm/master/_examples/interactive_multiselect/custom-keys/animation.svg)
Expand Down
32 changes: 32 additions & 0 deletions _examples/interactive_multiselect/custom-checkmarks/README.md
@@ -0,0 +1,32 @@
# interactive_multiselect/custom-checkmark

![Animation](animation.svg)

```go
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
printer.Checkmark = pterm.Checkmark{Checked: "+", Unchecked: "-"}
selectedOptions, _ := printer.Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}

```
44 changes: 44 additions & 0 deletions _examples/interactive_multiselect/custom-checkmarks/ci.go
@@ -0,0 +1,44 @@
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)
for i := 0; i < 10; i++ {
keyboard.SimulateKeyPress(keys.Down)
if i%2 == 0 {
time.Sleep(time.Millisecond * 100)
keyboard.SimulateKeyPress(keys.Enter)
}
time.Sleep(time.Millisecond * 500)
}
time.Sleep(time.Second)

for _, s := range "fuzzy" {
keyboard.SimulateKeyPress(s)
time.Sleep(time.Millisecond * 150)
}

time.Sleep(time.Second)

for i := 0; i < 2; i++ {
keyboard.SimulateKeyPress(keys.Down)
time.Sleep(time.Millisecond * 300)
}

keyboard.SimulateKeyPress(keys.Enter)
time.Sleep(time.Millisecond * 350)
keyboard.SimulateKeyPress(keys.Tab)
}()
}
}
25 changes: 25 additions & 0 deletions _examples/interactive_multiselect/custom-checkmarks/main.go
@@ -0,0 +1,25 @@
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
printer.Checkmark = pterm.Checkmark{Checked: "+", Unchecked: "-"}
selectedOptions, _ := printer.Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
6 changes: 6 additions & 0 deletions atoms.go
Expand Up @@ -11,6 +11,12 @@ type Bar struct {
LabelStyle *Style
}

// Checkmark is used in the interactive multiselect printer.
type Checkmark struct {
Checked string
Unchecked string
}

// WithLabel returns a new Bar with a specific option.
func (p Bar) WithLabel(s string) *Bar {
p.Label = s
Expand Down
16 changes: 14 additions & 2 deletions interactive_multiselect_printer.go
Expand Up @@ -8,6 +8,7 @@ import (
"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
"github.com/lithammer/fuzzysearch/fuzzy"

"github.com/pterm/pterm/internal"
)

Expand All @@ -25,6 +26,10 @@ var (
Filter: true,
KeySelect: keys.Enter,
KeyConfirm: keys.Tab,
Checkmark: Checkmark{
Checked: "✓",
Unchecked: "✗",
},
}
)

Expand All @@ -39,6 +44,7 @@ type InteractiveMultiselectPrinter struct {
Selector string
SelectorStyle *Style
Filter bool
Checkmark Checkmark

selectedOption int
selectedOptions []int
Expand Down Expand Up @@ -95,6 +101,12 @@ func (p InteractiveMultiselectPrinter) WithKeyConfirm(keyConfirm keys.KeyCode) *
return &p
}

// WithCheckmark sets the checkmark
func (p InteractiveMultiselectPrinter) WithCheckmark(checkmark Checkmark) *InteractiveMultiselectPrinter {
p.Checkmark = checkmark
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 @@ -345,9 +357,9 @@ func (p *InteractiveMultiselectPrinter) renderSelectMenu() string {
}
var checkmark string
if p.isSelected(option) {
checkmark = fmt.Sprintf("[%s]", Green("✓"))
checkmark = fmt.Sprintf("[%s]", Green(p.Checkmark.Checked))
} else {
checkmark = fmt.Sprintf("[%s]", Red("✗"))
checkmark = fmt.Sprintf("[%s]", Red(p.Checkmark.Unchecked))
}
if i == p.selectedOption {
content += Sprintf("%s %s %s\n", p.renderSelector(), checkmark, option)
Expand Down
68 changes: 68 additions & 0 deletions interactive_multiselect_printer_test.go
@@ -0,0 +1,68 @@
package pterm_test

import (
"testing"

"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
"github.com/MarvinJWendt/testza"

"github.com/pterm/pterm"
)

func TestInteractiveMultiselectPrinter_Show(t *testing.T) {
go func() {
keyboard.SimulateKeyPress(keys.Down)
keyboard.SimulateKeyPress(keys.Down)
keyboard.SimulateKeyPress(keys.Enter)
keyboard.SimulateKeyPress(keys.Tab)
}()
result, _ := pterm.DefaultInteractiveMultiselect.WithOptions([]string{"a", "b", "c", "d", "e"}).WithDefaultOptions([]string{"b"}).Show()
testza.AssertEqual(t, []string{"b", "c"}, result)
}

func TestInteractiveMultiselectPrinter_Show_MaxHeightSlidingWindow(t *testing.T) {
go func() {
keyboard.SimulateKeyPress(keys.Up)
keyboard.SimulateKeyPress(keys.Up)
keyboard.SimulateKeyPress(keys.Enter)
keyboard.SimulateKeyPress(keys.Tab)
}()
result, _ := pterm.DefaultInteractiveMultiselect.WithOptions([]string{"a", "b", "c", "d", "e", "f"}).WithDefaultOptions([]string{"b"}).Show()
testza.AssertEqual(t, []string{"b", "e"}, result)
}

func TestInteractiveMultiselectPrinter_WithDefaultText(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithDefaultText("default")
testza.AssertEqual(t, p.DefaultText, "default")
}

func TestInteractiveMultiselectPrinter_WithDefaultOption(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithDefaultOptions([]string{"default"})
testza.AssertEqual(t, p.DefaultOptions, []string{"default"})
}

func TestInteractiveMultiselectPrinter_WithOptions(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithOptions([]string{"a", "b", "c"})
testza.AssertEqual(t, p.Options, []string{"a", "b", "c"})
}

func TestInteractiveMultiselectPrinter_WithMaxHeight(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithMaxHeight(1337)
testza.AssertEqual(t, p.MaxHeight, 1337)
}

func TestInteractiveMultiselectPrinter_WithKeySelect(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithKeySelect(keys.Left).WithOptions([]string{"a", "b", "c"})
testza.AssertEqual(t, p.KeySelect, keys.Left)
}

func TestInteractiveMultiselectPrinter_WithKeyConfirm(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithKeyConfirm(keys.Left).WithOptions([]string{"a", "b", "c"})
testza.AssertEqual(t, p.KeyConfirm, keys.Left)
}

func TestInteractiveMultiselectPrinter_WithCheckmark(t *testing.T) {
p := pterm.DefaultInteractiveMultiselect.WithCheckmark(pterm.Checkmark{Checked: "+", Unchecked: "-"}).WithOptions([]string{"a", "b", "c"})
testza.AssertEqual(t, p.Checkmark, pterm.Checkmark{Checked: "+", Unchecked: "-"})
}

0 comments on commit 19c2c06

Please sign in to comment.