Skip to content

Commit

Permalink
Merge branch 'main' of github.com:reeflective/console
Browse files Browse the repository at this point in the history
  • Loading branch information
maxlandon committed Aug 9, 2024
2 parents f2f4b45 + 6eb126c commit 9753c8d
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 57 deletions.
37 changes: 37 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package console

import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

const (
Expand Down Expand Up @@ -73,3 +74,39 @@ next:

c.filters = updated
}

// resetFlagsDefaults resets all flags to their default values.
//
// Slice flags accumulate per execution (and do not reset),
//
// so we must reset them manually.
//
// Example:
//
// Given cmd.Flags().StringSlice("comment", nil, "")
// If you run a command with --comment "a" --comment "b" you will get
// the expected [a, b] slice.
//
// If you run a command again with no --comment flags, you will get
// [a, b] again instead of an empty slice.
//
// If you run the command again with --comment "c" --comment "d" flags,
// you will get [a, b, c, d] instead of just [c, d].
func resetFlagsDefaults(target *cobra.Command) {
target.Flags().VisitAll(func(flag *pflag.Flag) {
flag.Changed = false
switch value := flag.Value.(type) {
case pflag.SliceValue:
var res []string

if len(flag.DefValue) > 0 && flag.DefValue != "[]" {
res = append(res, flag.DefValue)
}

value.Replace(res)

default:
flag.Value.Set(flag.DefValue)
}
})
}
65 changes: 65 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package console

import (
"fmt"
"os"
)

type (
// ErrorHandler is a function that handles errors.
//
// The handler can choose not to bubble up the error by returning nil.
ErrorHandler func(err error) error

// Err is the Console base error type.
//
// All errors that bubble up to the error handler should be
// wrapped in this error type.
//
// There are more concrete error types that wrap this one defined below
// this allow for easy use of errors.As.
Err struct {
err error
message string
}

// PreReadError is an error that occurs during the pre-read phase.
PreReadError struct{ Err }

// ParseError is an error that occurs during the parsing phase.
ParseError struct{ Err }

// LineHookError is an error that occurs during the line hook phase.
LineHookError struct{ Err }

// ExecutionError is an error that occurs during the execution phase.
ExecutionError struct{ Err }
)

func defaultErrorHandler(err error) error {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)

return nil
}

// newError creates a new Err.
func newError(err error, message string) Err {
return Err{
err: err,
message: message,
}
}

// Error returns the error message with an optional
// message prefix.
func (e Err) Error() string {
if len(e.message) > 0 {
return fmt.Sprintf("%s: %s", e.message, e.err.Error())
}
return e.err.Error()
}

// Unwrap implements the errors Unwrap interface.
func (e Err) Unwrap() error {
return e.err
}
10 changes: 10 additions & 0 deletions example/main-commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ func mainMenuCommands(app *console.Console) console.Commands {
// Readline subcommands
rootCmd.AddCommand(readline.Commands(app.Shell()))

exitCmd := &cobra.Command{
Use: "exit",
Short: "Exit the console application",
GroupID: "core",
Run: func(cmd *cobra.Command, args []string) {
exitCtrlD(app)
},
}
rootCmd.AddCommand(exitCmd)

// And let's add a command declared in a traditional "cobra" way.
clientMenuCommand := &cobra.Command{
Use: "client",
Expand Down
6 changes: 3 additions & 3 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ func main() {

app.SetPrintLogo(func(_ *console.Console) {
fmt.Print(`
_____ __ _ _ _ _____ _
| __ \ / _| | | | (_) / ____| | |
| |__) |___ ___| |_| | ___ ___| |_ ___ _____ | | ___ _ __ ___ ___ | | ___
_____ __ _ _ _ _____ _
| __ \ / _| | | | (_) / ____| | |
| |__) |___ ___| |_| | ___ ___| |_ ___ _____ | | ___ _ __ ___ ___ | | ___
| _ // _ \/ _ \ _| |/ _ \/ __| __| \ \ / / _ \ | | / _ \| '_ \/ __|/ _ \| |/ _ \
| | \ \ __/ __/ | | | __/ (__| |_| |\ V / __/ | |___| (_) | | | \__ \ (_) | | __/
|_| \_\___|\___|_| |_|\___|\___|\__|_| \_/ \___| \_____\___/|_| |_|___/\___/|_|\___|
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ go 1.21

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

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rsteube/carapace-shlex v0.1.1 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/term v0.23.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/reeflective/readline v1.0.13 h1:TeJmYw9B7VRPZWfNExr9QHxL1m0iSicyqBSQIRn39Ss=
github.com/reeflective/readline v1.0.13/go.mod h1:3iOe/qyb2jEy0KqLrNlb/CojBVqxga9ACqz/VU22H6A=
github.com/reeflective/readline v1.0.15 h1:uB/M1sAc2yZGO14Ujgr/imLwQXqGdOhDDWAEHF+MBaE=
github.com/reeflective/readline v1.0.15/go.mod h1:3iOe/qyb2jEy0KqLrNlb/CojBVqxga9ACqz/VU22H6A=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rsteube/carapace v0.46.3-0.20231214181515-27e49f3c3b69 h1:ctOUuKn5PO6VtwtaS7unNrm6u20YXESPtnKEie/u304=
Expand All @@ -31,10 +35,16 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
Expand Down
9 changes: 6 additions & 3 deletions interrupt.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package console

// AddInterrupt registers a handler to run when the console receives a given
// interrupt error from the underlying readline shell. Mainly two interrupt
// signals are concerned: io.EOF (returned when pressing CtrlD), and console.ErrCtrlC.
// AddInterrupt registers a handler to run when the console receives
// a given interrupt error from the underlying readline shell.
//
// On most systems, the following errors will be returned with keypresses:
// - Linux/MacOS/Windows : Ctrl-C will return os.Interrupt.
//
// Many will want to use this to switch menus. Note that these interrupt errors only
// work when the console is NOT currently executing a command, only when reading input.
func (m *Menu) AddInterrupt(err error, handler func(c *Console)) {
Expand Down
6 changes: 6 additions & 0 deletions menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type Menu struct {
// Maps interrupt signals (CtrlC/IOF, etc) to specific error handlers.
interruptHandlers map[error]func(c *Console)

// ErrorHandler is called when an error is encountered.
//
// If not set, the error is printed to the console on os.Stderr.
ErrorHandler ErrorHandler

// Input/output channels
out *bytes.Buffer

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

// Add a default in memory history to each menu
Expand Down
Loading

0 comments on commit 9753c8d

Please sign in to comment.