Skip to content

Commit

Permalink
Provide Write(), Stderr(), Printf() methods on App (desertbit#14)
Browse files Browse the repository at this point in the history
* Provide Write() and Stderr() methods on App.

This allows consumers of the library to write in a manner that refreshes
the prompt because it goes through the Readline library.  This is useful
for background tasks or notifications to correctly redraw your screen.

This uses the readline terminal when available, otherwise it uses
os.Stdout.
  • Loading branch information
Matir authored Feb 2, 2020
1 parent 9690929 commit 1d9d68d
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 56 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ app.AddCommand(&grumble.Command{
},

Run: func(c *grumble.Context) error {
fmt.Println("timeout:", c.Flags.Duration("timeout"))
fmt.Println("directory:", c.Flags.String("directory"))
fmt.Println("verbose:", c.Flags.Bool("verbose"))
c.App.Println("timeout:", c.Flags.Duration("timeout"))
c.App.Println("directory:", c.Flags.String("directory"))
c.App.Println("verbose:", c.Flags.Bool("verbose"))

// Handle args.
fmt.Println("args:")
fmt.Println(strings.Join(c.Args, "\n"))
c.App.Println("args:")
c.App.Println(strings.Join(c.Args, "\n"))

return nil
},
Expand Down
41 changes: 38 additions & 3 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,25 @@ func (a *App) Commands() *Commands {
// PrintError prints the given error.
func (a *App) PrintError(err error) {
if a.config.NoColor {
fmt.Printf("error: %v\n", err)
a.Printf("error: %v\n", err)
} else {
a.config.ErrorColor.Print("error: ")
fmt.Printf("%v\n", err)
a.config.ErrorColor.Fprint(a, "error: ")
a.Printf("%v\n", err)
}
}

// Printf formats according to a format specifier and writes to terminal output.
// Printf writes to standard output if terminal output is not yet active.
func (a *App) Printf(format string, args ...interface{}) (int, error) {
return fmt.Fprintf(a, format, args...)
}

// Println writes to terminal output followed by a newline.
// Println writes to standard output if terminal output is not yet active.
func (a *App) Println(args ...interface{}) (int, error) {
return fmt.Fprintln(a, args...)
}

// OnInit sets the function which will be executed before the first command
// is executed. App flags can be handled here.
func (a *App) OnInit(f func(a *App, flags FlagMap) error) {
Expand Down Expand Up @@ -167,6 +179,29 @@ func (a *App) SetPrintASCIILogo(f func(a *App)) {
}
}

// Write to the underlying output, using readline if available.
func (a *App) Write(p []byte) (int, error) {
return a.Stdout().Write(p)
}

// Stdout returns a writer to Stdout, using readline if available.
// Note that calling before Run() will return a different instance.
func (a *App) Stdout() io.Writer {
if a.rl != nil {
return a.rl.Stdout()
}
return os.Stdout
}

// Stderr returns a writer to Stderr, using readline if available.
// Note that calling before Run() will return a different instance.
func (a *App) Stderr() io.Writer {
if a.rl != nil {
return a.rl.Stderr()
}
return os.Stderr
}

// AddCommand adds a new command.
// Panics on error.
func (a *App) AddCommand(cmd *Command) {
Expand Down
70 changes: 36 additions & 34 deletions functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ import (

func defaultInterruptHandler(a *App, count int) {
if count >= 2 {
fmt.Println("interrupted")
a.Println("interrupted")
os.Exit(1)
}
fmt.Println("input Ctrl-c once more to exit")
a.Println("input Ctrl-c once more to exit")
}

func defaultPrintHelp(a *App, shell bool) {
Expand All @@ -54,14 +54,14 @@ func defaultPrintHelp(a *App, shell bool) {

// Description.
if (len(a.config.Description)) > 0 {
fmt.Printf("\n%s\n", a.config.Description)
a.Printf("\n%s\n", a.config.Description)
}

// Usage.
if !shell {
fmt.Println()
printHeadline(a.config, "Usage:")
fmt.Printf(" %s [command]\n", a.config.Name)
a.Println()
printHeadline(a, "Usage:")
a.Printf(" %s [command]\n", a.config.Name)
}

// Group the commands by their help group if present.
Expand Down Expand Up @@ -101,9 +101,9 @@ func defaultPrintHelp(a *App, shell bool) {
}

if len(output) > 0 {
fmt.Println()
printHeadline(a.config, headline)
fmt.Printf("%s\n", columnize.Format(output, config))
a.Println()
printHeadline(a, headline)
a.Printf("%s\n", columnize.Format(output, config))
}
}

Expand All @@ -119,9 +119,9 @@ func defaultPrintHelp(a *App, shell bool) {
}
if hasSubCmds {
// Headline.
fmt.Println()
printHeadline(a.config, "Sub Commands:")
hp := headlinePrinter(a.config)
a.Println()
printHeadline(a, "Sub Commands:")
hp := headlinePrinter(a)

// Only print the first level of sub commands.
for _, c := range a.commands.list {
Expand All @@ -138,9 +138,9 @@ func defaultPrintHelp(a *App, shell bool) {
output = append(output, fmt.Sprintf("%s | %v", name, c.Help))
}

fmt.Println()
a.Println()
_, _ = hp(c.Name + ":")
fmt.Printf("%s\n", columnize.Format(output, config))
a.Printf("%s\n", columnize.Format(output, config))
}
}
}
Expand All @@ -150,7 +150,7 @@ func defaultPrintHelp(a *App, shell bool) {
printFlags(a, &a.flags)
}

fmt.Println()
a.Println()
}

func defaultPrintCommandHelp(a *App, cmd *Command, shell bool) {
Expand All @@ -162,16 +162,16 @@ func defaultPrintCommandHelp(a *App, cmd *Command, shell bool) {

// Help description.
if (len(cmd.LongHelp)) > 0 {
fmt.Printf("\n%s\n", cmd.LongHelp)
a.Printf("\n%s\n", cmd.LongHelp)
} else {
fmt.Printf("\n%s\n", cmd.Help)
a.Printf("\n%s\n", cmd.Help)
}

// Usage
if len(cmd.Usage) > 0 {
fmt.Println()
printHeadline(a.config, "Usage:")
fmt.Printf(" %s\n", cmd.Usage)
a.Println()
printHeadline(a, "Usage:")
a.Printf(" %s\n", cmd.Usage)
}

// Flags.
Expand All @@ -189,24 +189,26 @@ func defaultPrintCommandHelp(a *App, cmd *Command, shell bool) {
output = append(output, fmt.Sprintf("%s | %v", name, c.Help))
}

fmt.Println()
printHeadline(a.config, "Sub Commands:")
fmt.Printf("%s\n", columnize.Format(output, config))
a.Println()
printHeadline(a, "Sub Commands:")
a.Printf("%s\n", columnize.Format(output, config))
}

fmt.Println()
a.Println()
}

func headlinePrinter(c *Config) func(v ...interface{}) (int, error) {
if c.NoColor || c.HelpHeadlineColor == nil {
return fmt.Println
func headlinePrinter(a *App) func(v ...interface{}) (int, error) {
if a.config.NoColor || a.config.HelpHeadlineColor == nil {
return a.Println
}
return func(v ...interface{}) (int, error) {
return a.config.HelpHeadlineColor.Fprintln(a, v...)
}
return c.HelpHeadlineColor.Println
}

func printHeadline(c *Config, s string) {
hp := headlinePrinter(c)
if c.HelpHeadlineUnderline {
func printHeadline(a *App, s string) {
hp := headlinePrinter(a)
if a.config.HelpHeadlineUnderline {
_, _ = hp(s)
u := ""
for i := 0; i < len(s); i++ {
Expand Down Expand Up @@ -244,8 +246,8 @@ func printFlags(a *App, flags *Flags) {
}

if len(output) > 0 {
fmt.Println()
printHeadline(a.config, "Flags:")
fmt.Printf("%s\n", columnize.Format(output, config))
a.Println()
printHeadline(a, "Flags:")
a.Printf("%s\n", columnize.Format(output, config))
}
}
14 changes: 6 additions & 8 deletions sample/full/cmd/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
package cmd

import (
"fmt"

"github.com/desertbit/grumble"
"github.com/fatih/color"
)
Expand All @@ -49,11 +47,11 @@ var App = grumble.New(&grumble.Config{

func init() {
App.SetPrintASCIILogo(func(a *grumble.App) {
fmt.Println(" _ _ ")
fmt.Println(" ___ ___ _ _ _____| |_| |___ ")
fmt.Println("| . | _| | | | . | | -_|")
fmt.Println("|_ |_| |___|_|_|_|___|_|___|")
fmt.Println("|___| ")
fmt.Println()
a.Println(" _ _ ")
a.Println(" ___ ___ _ _ _____| |_| |___ ")
a.Println("| . | _| | | | . | | -_|")
a.Println("|_ |_| |___|_|_|_|___|_|___|")
a.Println("|___| ")
a.Println()
})
}
12 changes: 6 additions & 6 deletions sample/simple/cmd/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ func init() {
f.Duration("t", "timeout", time.Second, "timeout duration")
},
Run: func(c *grumble.Context) error {
fmt.Println("timeout:", c.Flags.Duration("timeout"))
fmt.Println("directory:", c.Flags.String("directory"))
fmt.Println("verbose:", c.Flags.Bool("verbose"))
c.App.Println("timeout:", c.Flags.Duration("timeout"))
c.App.Println("directory:", c.Flags.String("directory"))
c.App.Println("verbose:", c.Flags.Bool("verbose"))

// Handle args.
fmt.Println("args:")
fmt.Println(strings.Join(c.Args, "\n"))
c.App.Println("args:")
c.App.Println(strings.Join(c.Args, "\n"))

return nil
},
Expand All @@ -75,7 +75,7 @@ func init() {
Name: "root",
Help: "root the machine",
Run: func(c *grumble.Context) error {
fmt.Println(c.Flags.String("directory"))
c.App.Println(c.Flags.String("directory"))
return fmt.Errorf("failed!")
},
})
Expand Down

0 comments on commit 1d9d68d

Please sign in to comment.