Skip to content

Commit 9e33013

Browse files
authored
Merge branch 'main' into filter-select-all
2 parents 4824a75 + f921ebd commit 9e33013

File tree

16 files changed

+113
-59
lines changed

16 files changed

+113
-59
lines changed

choose/choose.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,18 @@ func defaultKeymap() keymap {
2424
return keymap{
2525
Down: key.NewBinding(
2626
key.WithKeys("down", "j", "ctrl+j", "ctrl+n"),
27-
key.WithHelp("↓", "down"),
2827
),
2928
Up: key.NewBinding(
3029
key.WithKeys("up", "k", "ctrl+k", "ctrl+p"),
31-
key.WithHelp("↑", "up"),
3230
),
3331
Right: key.NewBinding(
3432
key.WithKeys("right", "l", "ctrl+f"),
35-
key.WithHelp("→", "right"),
3633
),
3734
Left: key.NewBinding(
3835
key.WithKeys("left", "h", "ctrl+b"),
39-
key.WithHelp("←", "left"),
4036
),
4137
Home: key.NewBinding(
4238
key.WithKeys("g", "home"),
43-
key.WithHelp("g", "home"),
4439
),
4540
End: key.NewBinding(
4641
key.WithKeys("G", "end"),
@@ -57,9 +52,13 @@ func defaultKeymap() keymap {
5752
key.WithDisabled(),
5853
),
5954
Abort: key.NewBinding(
60-
key.WithKeys("ctrl+c", "esc"),
55+
key.WithKeys("ctrl+c"),
6156
key.WithHelp("ctrl+c", "abort"),
6257
),
58+
Quit: key.NewBinding(
59+
key.WithKeys("esc"),
60+
key.WithHelp("esc", "quit"),
61+
),
6362
Submit: key.NewBinding(
6463
key.WithKeys("enter", "ctrl+q"),
6564
key.WithHelp("enter", "submit"),
@@ -77,6 +76,7 @@ type keymap struct {
7776
ToggleAll,
7877
Toggle,
7978
Abort,
79+
Quit,
8080
Submit key.Binding
8181
}
8282

@@ -89,7 +89,7 @@ func (k keymap) ShortHelp() []key.Binding {
8989
k.Toggle,
9090
key.NewBinding(
9191
key.WithKeys("up", "down", "right", "left"),
92-
key.WithHelp("↑↓←→", "navigate"),
92+
key.WithHelp("←↓↑→", "navigate"),
9393
),
9494
k.Submit,
9595
k.ToggleAll,
@@ -105,6 +105,7 @@ type model struct {
105105
header string
106106
items []item
107107
quitting bool
108+
submitted bool
108109
index int
109110
limit int
110111
numSelected int
@@ -177,6 +178,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
177178
} else {
178179
m = m.deselectAll()
179180
}
181+
case key.Matches(msg, km.Quit):
182+
m.quitting = true
183+
return m, tea.Quit
180184
case key.Matches(msg, km.Abort):
181185
m.quitting = true
182186
return m, tea.Interrupt
@@ -199,6 +203,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
199203
if m.limit <= 1 && m.numSelected < 1 {
200204
m.items[m.index].selected = true
201205
}
206+
m.submitted = true
202207
return m, tea.Quit
203208
}
204209
}

choose/command.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ func (o Options) Run() error {
5555
slices.SortFunc(o.Options, strings.Compare)
5656
}
5757

58+
isSelectAll := len(o.Selected) == 1 && o.Selected[0] == "*"
59+
5860
// Keep track of the selected items.
5961
currentSelected := 0
6062
// Check if selected items should be used.
@@ -65,7 +67,7 @@ func (o Options) Run() error {
6567
for i, option := range o.Options {
6668
var order int
6769
// Check if the option should be selected.
68-
isSelected := hasSelectedItems && currentSelected < o.Limit && slices.Contains(o.Selected, option)
70+
isSelected := hasSelectedItems && currentSelected < o.Limit && (isSelectAll || slices.Contains(o.Selected, option))
6971
// If the option is selected then increment the current selected count.
7072
if isSelected {
7173
if o.Limit == 1 {
@@ -136,6 +138,9 @@ func (o Options) Run() error {
136138
return fmt.Errorf("unable to pick selection: %w", err)
137139
}
138140
m = tm.(model)
141+
if !m.submitted {
142+
return errors.New("nothing selected")
143+
}
139144
if o.Ordered && o.Limit > 1 {
140145
sort.Slice(m.items, func(i, j int) bool {
141146
return m.items[i].order < m.items[j].order

choose/options.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,23 @@ import (
88

99
// Options is the customization options for the choose command.
1010
type Options struct {
11-
Options []string `arg:"" optional:"" help:"Options to choose from."`
12-
Limit int `help:"Maximum number of options to pick" default:"1" group:"Selection"`
13-
NoLimit bool `help:"Pick unlimited number of options (ignores limit)" group:"Selection"`
14-
Ordered bool `help:"Maintain the order of the selected options" env:"GUM_CHOOSE_ORDERED"`
15-
Height int `help:"Height of the list" default:"10" env:"GUM_CHOOSE_HEIGHT"`
16-
Cursor string `help:"Prefix to show on item that corresponds to the cursor position" default:"> " env:"GUM_CHOOSE_CURSOR"`
17-
ShowHelp bool `help:"Show help keybinds" default:"true" negatable:"" env:"GUM_CHOOSE_SHOW_HELP"`
18-
Header string `help:"Header value" default:"Choose:" env:"GUM_CHOOSE_HEADER"`
19-
CursorPrefix string `help:"Prefix to show on the cursor item (hidden if limit is 1)" default:"• " env:"GUM_CHOOSE_CURSOR_PREFIX"`
20-
SelectedPrefix string `help:"Prefix to show on selected items (hidden if limit is 1)" default:"✓ " env:"GUM_CHOOSE_SELECTED_PREFIX"`
21-
UnselectedPrefix string `help:"Prefix to show on unselected items (hidden if limit is 1)" default:"• " env:"GUM_CHOOSE_UNSELECTED_PREFIX"`
22-
Selected []string `help:"Options that should start as selected" default:"" env:"GUM_CHOOSE_SELECTED"`
23-
SelectIfOne bool `help:"Select the given option if there is only one" group:"Selection"`
24-
CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=212" envprefix:"GUM_CHOOSE_CURSOR_"`
25-
HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=99" envprefix:"GUM_CHOOSE_HEADER_"`
26-
ItemStyle style.Styles `embed:"" prefix:"item." hidden:"" envprefix:"GUM_CHOOSE_ITEM_"`
27-
SelectedItemStyle style.Styles `embed:"" prefix:"selected." set:"defaultForeground=212" envprefix:"GUM_CHOOSE_SELECTED_"`
28-
Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0s" env:"GUM_CCHOOSE_TIMEOUT"` // including timeout command options [Timeout,...]
11+
Options []string `arg:"" optional:"" help:"Options to choose from."`
12+
Limit int `help:"Maximum number of options to pick" default:"1" group:"Selection"`
13+
NoLimit bool `help:"Pick unlimited number of options (ignores limit)" group:"Selection"`
14+
Ordered bool `help:"Maintain the order of the selected options" env:"GUM_CHOOSE_ORDERED"`
15+
Height int `help:"Height of the list" default:"10" env:"GUM_CHOOSE_HEIGHT"`
16+
Cursor string `help:"Prefix to show on item that corresponds to the cursor position" default:"> " env:"GUM_CHOOSE_CURSOR"`
17+
ShowHelp bool `help:"Show help keybinds" default:"true" negatable:"" env:"GUM_CHOOSE_SHOW_HELP"`
18+
Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0s" env:"GUM_CCHOOSE_TIMEOUT"` // including timeout command options [Timeout,...]
19+
Header string `help:"Header value" default:"Choose:" env:"GUM_CHOOSE_HEADER"`
20+
CursorPrefix string `help:"Prefix to show on the cursor item (hidden if limit is 1)" default:"• " env:"GUM_CHOOSE_CURSOR_PREFIX"`
21+
SelectedPrefix string `help:"Prefix to show on selected items (hidden if limit is 1)" default:"✓ " env:"GUM_CHOOSE_SELECTED_PREFIX"`
22+
UnselectedPrefix string `help:"Prefix to show on unselected items (hidden if limit is 1)" default:"• " env:"GUM_CHOOSE_UNSELECTED_PREFIX"`
23+
Selected []string `help:"Options that should start as selected (selects all if given '*')" default:"" env:"GUM_CHOOSE_SELECTED"`
24+
SelectIfOne bool `help:"Select the given option if there is only one" group:"Selection"`
25+
26+
CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=212" envprefix:"GUM_CHOOSE_CURSOR_"`
27+
HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=99" envprefix:"GUM_CHOOSE_HEADER_"`
28+
ItemStyle style.Styles `embed:"" prefix:"item." hidden:"" envprefix:"GUM_CHOOSE_ITEM_"`
29+
SelectedItemStyle style.Styles `embed:"" prefix:"selected." set:"defaultForeground=212" envprefix:"GUM_CHOOSE_SELECTED_"`
2930
}

confirm/confirm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func defaultKeymap(affirmative, negative string) keymap {
4747
"ctrl+p",
4848
"tab",
4949
),
50-
key.WithHelp("←/→", "toggle"),
50+
key.WithHelp("←→", "toggle"),
5151
),
5252
Submit: key.NewBinding(
5353
key.WithKeys("enter"),

file/command.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ func (o Options) Run() error {
4747
fp.Styles.Selected = o.SelectedStyle.ToLipgloss()
4848
fp.Styles.FileSize = o.FileSizeStyle.ToLipgloss()
4949
m := model{
50-
filepicker: fp,
51-
showHelp: o.ShowHelp,
52-
help: help.New(),
53-
keymap: defaultKeymap(),
50+
filepicker: fp,
51+
showHelp: o.ShowHelp,
52+
help: help.New(),
53+
keymap: defaultKeymap(),
54+
headerStyle: o.HeaderStyle.ToLipgloss(),
55+
header: o.Header,
5456
}
5557

5658
ctx, cancel := timeout.Context(o.Timeout)

file/file.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ var keyAbort = key.NewBinding(
3434

3535
func defaultKeymap() keymap {
3636
km := filepicker.DefaultKeyMap()
37-
km.Down.SetHelp("↓", "down")
38-
km.Up.SetHelp("↑", "up")
3937
return keymap(km)
4038
}
4139

@@ -45,14 +43,18 @@ func (k keymap) FullHelp() [][]key.Binding { return nil }
4543
// ShortHelp implements help.KeyMap.
4644
func (k keymap) ShortHelp() []key.Binding {
4745
return []key.Binding{
48-
k.Up,
49-
k.Down,
46+
key.NewBinding(
47+
key.WithKeys("up", "down"),
48+
key.WithHelp("↓↑", "navigate"),
49+
),
5050
keyQuit,
5151
k.Select,
5252
}
5353
}
5454

5555
type model struct {
56+
header string
57+
headerStyle lipgloss.Style
5658
filepicker filepicker.Model
5759
selectedPath string
5860
quitting bool
@@ -93,10 +95,15 @@ func (m model) View() string {
9395
if m.quitting {
9496
return ""
9597
}
96-
if !m.showHelp {
97-
return m.filepicker.View()
98+
var parts []string
99+
if m.header != "" {
100+
parts = append(parts, m.headerStyle.Render(m.header))
98101
}
99-
return m.filepicker.View() + m.helpView()
102+
parts = append(parts, m.filepicker.View())
103+
if m.showHelp {
104+
parts = append(parts, m.helpView())
105+
}
106+
return lipgloss.JoinVertical(lipgloss.Left, parts...)
100107
}
101108

102109
func (m model) helpView() string {

file/options.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ type Options struct {
1111
// Path is the path to the folder / directory to begin traversing.
1212
Path string `arg:"" optional:"" name:"path" help:"The path to the folder to begin traversing" env:"GUM_FILE_PATH"`
1313
// Cursor is the character to display in front of the current selected items.
14-
Cursor string `short:"c" help:"The cursor character" default:">" env:"GUM_FILE_CURSOR"`
15-
All bool `short:"a" help:"Show hidden and 'dot' files" default:"false" env:"GUM_FILE_ALL"`
16-
Permissions bool `short:"p" help:"Show file permissions" default:"true" negatable:"" env:"GUM_FILE_PERMISSION"`
17-
Size bool `short:"s" help:"Show file size" default:"true" negatable:"" env:"GUM_FILE_SIZE"`
18-
File bool `help:"Allow files selection" default:"true" env:"GUM_FILE_FILE"`
19-
Directory bool `help:"Allow directories selection" default:"false" env:"GUM_FILE_DIRECTORY"`
20-
ShowHelp bool `help:"Show help key binds" negatable:"" default:"true" env:"GUM_FILE_SHOW_HELP"`
14+
Cursor string `short:"c" help:"The cursor character" default:">" env:"GUM_FILE_CURSOR"`
15+
All bool `short:"a" help:"Show hidden and 'dot' files" default:"false" env:"GUM_FILE_ALL"`
16+
Permissions bool `short:"p" help:"Show file permissions" default:"true" negatable:"" env:"GUM_FILE_PERMISSION"`
17+
Size bool `short:"s" help:"Show file size" default:"true" negatable:"" env:"GUM_FILE_SIZE"`
18+
File bool `help:"Allow files selection" default:"true" env:"GUM_FILE_FILE"`
19+
Directory bool `help:"Allow directories selection" default:"false" env:"GUM_FILE_DIRECTORY"`
20+
ShowHelp bool `help:"Show help key binds" negatable:"" default:"true" env:"GUM_FILE_SHOW_HELP"`
21+
Timeout time.Duration `help:"Timeout until command aborts without a selection" default:"0s" env:"GUM_FILE_TIMEOUT"`
22+
Header string `help:"Header value" default:"" env:"GUM_FILE_HEADER"`
23+
Height int `help:"Maximum number of files to display" default:"10" env:"GUM_FILE_HEIGHT"`
2124

22-
Height int `help:"Maximum number of files to display" default:"10" env:"GUM_FILE_HEIGHT"`
2325
CursorStyle style.Styles `embed:"" prefix:"cursor." help:"The cursor style" set:"defaultForeground=212" envprefix:"GUM_FILE_CURSOR_"`
2426
SymlinkStyle style.Styles `embed:"" prefix:"symlink." help:"The style to use for symlinks" set:"defaultForeground=36" envprefix:"GUM_FILE_SYMLINK_"`
2527
DirectoryStyle style.Styles `embed:"" prefix:"directory." help:"The style to use for directories" set:"defaultForeground=99" envprefix:"GUM_FILE_DIRECTORY_"`
2628
FileStyle style.Styles `embed:"" prefix:"file." help:"The style to use for files" envprefix:"GUM_FILE_FILE_"`
2729
PermissionsStyle style.Styles `embed:"" prefix:"permissions." help:"The style to use for permissions" set:"defaultForeground=244" envprefix:"GUM_FILE_PERMISSIONS_"`
28-
//nolint:staticcheck
29-
SelectedStyle style.Styles `embed:"" prefix:"selected." help:"The style to use for the selected item" set:"defaultBold=true" set:"defaultForeground=212" envprefix:"GUM_FILE_SELECTED_"`
30-
//nolint:staticcheck
31-
FileSizeStyle style.Styles `embed:"" prefix:"file-size." help:"The style to use for file sizes" set:"defaultWidth=8" set:"defaultAlign=right" set:"defaultForeground=240" envprefix:"GUM_FILE_FILE_SIZE_"`
32-
Timeout time.Duration `help:"Timeout until command aborts without a selection" default:"0s" env:"GUM_FILE_TIMEOUT"`
30+
SelectedStyle style.Styles `embed:"" prefix:"selected." help:"The style to use for the selected item" set:"defaultBold=true" set:"defaultForeground=212" envprefix:"GUM_FILE_SELECTED_"` //nolint:staticcheck
31+
FileSizeStyle style.Styles `embed:"" prefix:"file-size." help:"The style to use for file sizes" set:"defaultWidth=8" set:"defaultAlign=right" set:"defaultForeground=240" envprefix:"GUM_FILE_FILE_SIZE_"` //nolint:staticcheck
32+
HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=99" envprefix:"GUM_FILE_HEADER_"`
3333
}

filter/command.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ func (o Options) Run() error {
120120
}
121121

122122
m := tm.(model)
123+
if !m.submitted {
124+
return errors.New("nothing selected")
125+
}
123126
isTTY := term.IsTerminal(os.Stdout.Fd())
124127

125128
// allSelections contains values only if limit is greater

filter/filter.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ func defaultKeymap() keymap {
2626
return keymap{
2727
Down: key.NewBinding(
2828
key.WithKeys("down", "ctrl+j", "ctrl+n"),
29-
key.WithHelp("↓", "down"),
3029
),
3130
Up: key.NewBinding(
3231
key.WithKeys("up", "ctrl+k", "ctrl+p"),
33-
key.WithHelp("↑", "up"),
3432
),
3533
ToggleAndNext: key.NewBinding(
3634
key.WithKeys("tab"),
@@ -52,8 +50,12 @@ func defaultKeymap() keymap {
5250
key.WithHelp("ctrl+a", "select all"),
5351
key.WithDisabled(),
5452
),
53+
Quit: key.NewBinding(
54+
key.WithKeys("esc"),
55+
key.WithHelp("esc", "quit"),
56+
),
5557
Abort: key.NewBinding(
56-
key.WithKeys("ctrl+c", "esc"),
58+
key.WithKeys("ctrl+c"),
5759
key.WithHelp("ctrl+c", "abort"),
5860
),
5961
Submit: key.NewBinding(
@@ -71,6 +73,7 @@ type keymap struct {
7173
ToggleAll,
7274
Toggle,
7375
Abort,
76+
Quit,
7477
Submit key.Binding
7578
}
7679

@@ -82,7 +85,7 @@ func (k keymap) ShortHelp() []key.Binding {
8285
return []key.Binding{
8386
key.NewBinding(
8487
key.WithKeys("up", "down"),
85-
key.WithHelp("↑↓", "navigate"),
88+
key.WithHelp("↓↑", "navigate"),
8689
),
8790
k.ToggleAndNext,
8891
k.ToggleAll,
@@ -119,6 +122,7 @@ type model struct {
119122
keymap keymap
120123
help help.Model
121124
strict bool
125+
submitted bool
122126
}
123127

124128
func (m model) Init() tea.Cmd { return textinput.Blink }
@@ -258,11 +262,15 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
258262
case tea.KeyMsg:
259263
km := m.keymap
260264
switch {
265+
case key.Matches(msg, km.Quit):
266+
m.quitting = true
267+
return m, tea.Quit
261268
case key.Matches(msg, km.Abort):
262269
m.quitting = true
263270
return m, tea.Interrupt
264271
case key.Matches(msg, km.Submit):
265272
m.quitting = true
273+
m.submitted = true
266274
return m, tea.Quit
267275
case key.Matches(msg, km.Down):
268276
m.CursorDown()

gum.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ type Gum struct {
133133
// │ 7 │ │
134134
// │ 8 │ │
135135
// ╰────────────────────────────────────────────────╯
136-
// ↑/↓: Navigate • q: Quit
136+
// ↓↑: navigate • q: quit
137137
//
138138
Pager pager.Options `cmd:"" help:"Scroll through a file"`
139139

input/command.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package input
22

33
import (
4+
"errors"
45
"fmt"
56
"os"
67

@@ -67,6 +68,9 @@ func (o Options) Run() error {
6768
}
6869

6970
m = tm.(model)
71+
if !m.submitted {
72+
return errors.New("not submitted")
73+
}
7074
fmt.Println(m.textinput.Value())
7175
return nil
7276
}

input/input.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type model struct {
4141
headerStyle lipgloss.Style
4242
textinput textinput.Model
4343
quitting bool
44+
submitted bool
4445
showHelp bool
4546
help help.Model
4647
keymap keymap
@@ -79,9 +80,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7980
case "ctrl+c":
8081
m.quitting = true
8182
return m, tea.Interrupt
82-
case "esc", "enter":
83+
case "esc":
8384
m.quitting = true
8485
return m, tea.Quit
86+
case "enter":
87+
m.quitting = true
88+
m.submitted = true
89+
return m, tea.Quit
8590
}
8691
}
8792

pager/pager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func (k keymap) ShortHelp() []key.Binding {
3838
return []key.Binding{
3939
key.NewBinding(
4040
key.WithKeys("up", "down"),
41-
key.WithHelp("↑/↓", "navigate"),
41+
key.WithHelp("↓↑", "navigate"),
4242
),
4343
k.Quit,
4444
k.Search,

0 commit comments

Comments
 (0)