Skip to content

Commit 9753c8d

Browse files
committed
Merge branch 'main' of github.com:reeflective/console
2 parents f2f4b45 + 6eb126c commit 9753c8d

File tree

9 files changed

+204
-57
lines changed

9 files changed

+204
-57
lines changed

command.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package console
22

33
import (
44
"github.com/spf13/cobra"
5+
"github.com/spf13/pflag"
56
)
67

78
const (
@@ -73,3 +74,39 @@ next:
7374

7475
c.filters = updated
7576
}
77+
78+
// resetFlagsDefaults resets all flags to their default values.
79+
//
80+
// Slice flags accumulate per execution (and do not reset),
81+
//
82+
// so we must reset them manually.
83+
//
84+
// Example:
85+
//
86+
// Given cmd.Flags().StringSlice("comment", nil, "")
87+
// If you run a command with --comment "a" --comment "b" you will get
88+
// the expected [a, b] slice.
89+
//
90+
// If you run a command again with no --comment flags, you will get
91+
// [a, b] again instead of an empty slice.
92+
//
93+
// If you run the command again with --comment "c" --comment "d" flags,
94+
// you will get [a, b, c, d] instead of just [c, d].
95+
func resetFlagsDefaults(target *cobra.Command) {
96+
target.Flags().VisitAll(func(flag *pflag.Flag) {
97+
flag.Changed = false
98+
switch value := flag.Value.(type) {
99+
case pflag.SliceValue:
100+
var res []string
101+
102+
if len(flag.DefValue) > 0 && flag.DefValue != "[]" {
103+
res = append(res, flag.DefValue)
104+
}
105+
106+
value.Replace(res)
107+
108+
default:
109+
flag.Value.Set(flag.DefValue)
110+
}
111+
})
112+
}

errors.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package console
2+
3+
import (
4+
"fmt"
5+
"os"
6+
)
7+
8+
type (
9+
// ErrorHandler is a function that handles errors.
10+
//
11+
// The handler can choose not to bubble up the error by returning nil.
12+
ErrorHandler func(err error) error
13+
14+
// Err is the Console base error type.
15+
//
16+
// All errors that bubble up to the error handler should be
17+
// wrapped in this error type.
18+
//
19+
// There are more concrete error types that wrap this one defined below
20+
// this allow for easy use of errors.As.
21+
Err struct {
22+
err error
23+
message string
24+
}
25+
26+
// PreReadError is an error that occurs during the pre-read phase.
27+
PreReadError struct{ Err }
28+
29+
// ParseError is an error that occurs during the parsing phase.
30+
ParseError struct{ Err }
31+
32+
// LineHookError is an error that occurs during the line hook phase.
33+
LineHookError struct{ Err }
34+
35+
// ExecutionError is an error that occurs during the execution phase.
36+
ExecutionError struct{ Err }
37+
)
38+
39+
func defaultErrorHandler(err error) error {
40+
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
41+
42+
return nil
43+
}
44+
45+
// newError creates a new Err.
46+
func newError(err error, message string) Err {
47+
return Err{
48+
err: err,
49+
message: message,
50+
}
51+
}
52+
53+
// Error returns the error message with an optional
54+
// message prefix.
55+
func (e Err) Error() string {
56+
if len(e.message) > 0 {
57+
return fmt.Sprintf("%s: %s", e.message, e.err.Error())
58+
}
59+
return e.err.Error()
60+
}
61+
62+
// Unwrap implements the errors Unwrap interface.
63+
func (e Err) Unwrap() error {
64+
return e.err
65+
}

example/main-commands.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ func mainMenuCommands(app *console.Console) console.Commands {
3232
// Readline subcommands
3333
rootCmd.AddCommand(readline.Commands(app.Shell()))
3434

35+
exitCmd := &cobra.Command{
36+
Use: "exit",
37+
Short: "Exit the console application",
38+
GroupID: "core",
39+
Run: func(cmd *cobra.Command, args []string) {
40+
exitCtrlD(app)
41+
},
42+
}
43+
rootCmd.AddCommand(exitCmd)
44+
3545
// And let's add a command declared in a traditional "cobra" way.
3646
clientMenuCommand := &cobra.Command{
3747
Use: "client",

example/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ func main() {
2222

2323
app.SetPrintLogo(func(_ *console.Console) {
2424
fmt.Print(`
25-
_____ __ _ _ _ _____ _
26-
| __ \ / _| | | | (_) / ____| | |
27-
| |__) |___ ___| |_| | ___ ___| |_ ___ _____ | | ___ _ __ ___ ___ | | ___
25+
_____ __ _ _ _ _____ _
26+
| __ \ / _| | | | (_) / ____| | |
27+
| |__) |___ ___| |_| | ___ ___| |_ ___ _____ | | ___ _ __ ___ ___ | | ___
2828
| _ // _ \/ _ \ _| |/ _ \/ __| __| \ \ / / _ \ | | / _ \| '_ \/ __|/ _ \| |/ _ \
2929
| | \ \ __/ __/ | | | __/ (__| |_| |\ V / __/ | |___| (_) | | | \__ \ (_) | | __/
3030
|_| \_\___|\___|_| |_|\___|\___|\__|_| \_/ \___| \_____\___/|_| |_|___/\___/|_|\___|

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ go 1.21
44

55
require (
66
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
7-
github.com/reeflective/readline v1.0.13
7+
github.com/reeflective/readline v1.0.15
88
github.com/rsteube/carapace v0.46.3-0.20231214181515-27e49f3c3b69
99
github.com/spf13/cobra v1.8.0
1010
github.com/spf13/pflag v1.0.5
11-
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611
11+
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
1212
mvdan.cc/sh/v3 v3.7.0
1313
)
1414

1515
require (
1616
github.com/inconshreveable/mousetrap v1.1.0 // indirect
17-
github.com/rivo/uniseg v0.4.4 // indirect
17+
github.com/rivo/uniseg v0.4.7 // indirect
1818
github.com/rsteube/carapace-shlex v0.1.1 // indirect
19-
golang.org/x/sys v0.15.0 // indirect
20-
golang.org/x/term v0.15.0 // indirect
19+
golang.org/x/sys v0.24.0 // indirect
20+
golang.org/x/term v0.23.0 // indirect
2121
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
2222
gopkg.in/yaml.v3 v3.0.1 // indirect
2323
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
1616
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
1717
github.com/reeflective/readline v1.0.13 h1:TeJmYw9B7VRPZWfNExr9QHxL1m0iSicyqBSQIRn39Ss=
1818
github.com/reeflective/readline v1.0.13/go.mod h1:3iOe/qyb2jEy0KqLrNlb/CojBVqxga9ACqz/VU22H6A=
19+
github.com/reeflective/readline v1.0.15 h1:uB/M1sAc2yZGO14Ujgr/imLwQXqGdOhDDWAEHF+MBaE=
20+
github.com/reeflective/readline v1.0.15/go.mod h1:3iOe/qyb2jEy0KqLrNlb/CojBVqxga9ACqz/VU22H6A=
1921
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
2022
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
23+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
24+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
2125
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
2226
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
2327
github.com/rsteube/carapace v0.46.3-0.20231214181515-27e49f3c3b69 h1:ctOUuKn5PO6VtwtaS7unNrm6u20YXESPtnKEie/u304=
@@ -31,10 +35,16 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
3135
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
3236
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4=
3337
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
38+
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
39+
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
3440
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
3541
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
42+
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
43+
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3644
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
3745
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
46+
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
47+
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
3848
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3949
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
4050
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

interrupt.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package console
22

3-
// AddInterrupt registers a handler to run when the console receives a given
4-
// interrupt error from the underlying readline shell. Mainly two interrupt
5-
// signals are concerned: io.EOF (returned when pressing CtrlD), and console.ErrCtrlC.
3+
// AddInterrupt registers a handler to run when the console receives
4+
// a given interrupt error from the underlying readline shell.
5+
//
6+
// On most systems, the following errors will be returned with keypresses:
7+
// - Linux/MacOS/Windows : Ctrl-C will return os.Interrupt.
8+
//
69
// Many will want to use this to switch menus. Note that these interrupt errors only
710
// work when the console is NOT currently executing a command, only when reading input.
811
func (m *Menu) AddInterrupt(err error, handler func(c *Console)) {

menu.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ type Menu struct {
2626
// Maps interrupt signals (CtrlC/IOF, etc) to specific error handlers.
2727
interruptHandlers map[error]func(c *Console)
2828

29+
// ErrorHandler is called when an error is encountered.
30+
//
31+
// If not set, the error is printed to the console on os.Stderr.
32+
ErrorHandler ErrorHandler
33+
2934
// Input/output channels
3035
out *bytes.Buffer
3136

@@ -60,6 +65,7 @@ func newMenu(name string, console *Console) *Menu {
6065
interruptHandlers: make(map[error]func(c *Console)),
6166
histories: make(map[string]readline.History),
6267
mutex: &sync.RWMutex{},
68+
ErrorHandler: defaultErrorHandler,
6369
}
6470

6571
// Add a default in memory history to each menu

0 commit comments

Comments
 (0)