π§ π§ π§ Work-in-Progress: See v1
Roadmap; Breaking changes may occur during v0
development.
Go library designed for command-line applications interacting with humans, providing delightful end-user experience for informational messaging via colourful, lightly structured messages with emojis.
demo.mp4
β Β This tool is for Informational messaging for the end-user while the command is running:
Messages are written into standard error stream (stderr
) to avoid polluting the actual program output in standard output stream (stdout
); Hence the messages are intended for end-user communication during the program runtime, not for the actual parseable result output:
Not everything on stderr is an error though. For example, you can use
curl
to download a file but the progress output is on stderr. This allows you to redirect the stdout while still seeing the progress.In short:
stdout
is for output,stderr
is for messaging.
β Β This tool is NOT for:
-
Log Events for tracing/debugging the program execution
β Use logging frameworks such as zap, zerolog or logrus for more advanced application logging. You still should ensure they write tostderr
(or to a rotated log file or something). -
Command Output (i.e. the result) written into
stdout
(which could be redirected to a file for example)
β Usefmt.Print
for that which defaults to writing into standard output.
-
Coloured output with emoji prefixes by default
-
Subprocess friendly: Tries to access the
tty
and print directly into it:- Useful if you're building a "plugin program" that some other program executes (and you can not control how it redirects the
stderr
of your program); For example the original purpose for this was to support AWScredential_process
where this happens some times. - In case
tty
not available, prints to Standard Error stream (stderr
). - Configurable: You may assign any
io.Writer
as the output target.
- Useful if you're building a "plugin program" that some other program executes (and you can not control how it redirects the
-
Respectful of environment, end-user can set environment variables to:
- disable color
- disable emoji
- enable silent mode
- verbose mode
go get github.com/aripalo/go-delightful
For example usage, see (Not yet implemented!)vegas-credentials
which utilizes this library.
Here are some of the basic methods:
package main
import (
"github.com/aripalo/go-delightful"
)
func main() {
// Initialize
message := delightful.New("demo")
// Purple message line
message.Titleln("π·", "Just showing things around here")
// Gray message line
message.Infoln("βΉοΈ", "Good to know")
// Cyan message (without newline)
message.Prompt("π", "Provide input")
// Green message line
message.Successln("β
", "Great Success")
// Red message line
message.Failureln("β", "Error")
}
An example command-line application using aripalo/go-delightful
:
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"github.com/aripalo/go-delightful"
"github.com/enescakir/emoji"
flag "github.com/spf13/pflag"
)
func main() {
// Initialize
message := delightful.New("greet")
// Some setup with spf13/pflag, not really important for this example
var silentMode bool
var verboseMode bool
var noEmoji bool
var noColor bool
flag.BoolVarP(&silentMode, "silent", "s", false, "silent mode (hides everything except prompt/failure messages)")
flag.BoolVar(&verboseMode, "verbose", false, "verbose output (show everything, overrides silent mode)")
flag.BoolVar(&noEmoji, "no-emoji", false, "disable emojis")
flag.BoolVar(&noColor, "no-color", false, "disable colors and emojis")
flag.Parse()
// Configure how messaging works based on above CLI flags
message.SetSilentMode(silentMode)
message.SetVerboseMode(verboseMode)
message.SetEmojiMode(!noEmoji)
message.SetColorMode(!noColor)
// Print a "banner" showing your app name and other (optional) info.
// Banner optional info only printed if in verbose mode.
message.Banner(delightful.BannerOptions{
Version: "v0.0.1",
Website: "http://example.com",
Command: "hello",
Extra: "Some extra info, let's keep it short!",
})
// Print "title" message line in purple.
message.Titleln("π₯", "This is going to be lit!")
// Print "debug" message line in dark gray.
// Only printed if in verbose mode.
message.Debugln("", "This is only visible if in verbose mode") // passing empty string for emoji disables it
// Print "info" message line in gray.
message.Infoln("βΉοΈ", "Just something for your information.")
// Print "prompt" message in cyan.
// Does not actually read input, only shows the "question".
message.Prompt("π", "Tell us Your name: ")
// Actually query the name via stdin
reader := bufio.NewReader(os.Stdin)
value, err := reader.ReadString('\n')
if err != nil {
// Print "failure" message line in red.
message.Failure("β", "galaxies exploded")
log.Fatal(err)
}
name := strings.TrimSpace(value)
if strings.ContainsRune(name, 'π©') {
// Unfortunately many environments print gendered/toned emojis incorrectly
// so you might want to use github.com/enescakir/emoji to assign "neutral" emoji
facepalm := emoji.Emoji(emoji.PersonFacepalming.Tone(emoji.Default))
// Print "warning" message line in yellow.
message.Warningln(facepalm, "Really? Your name has a poop emoji? You're being silly...")
} else {
// Print "success" message line in green.
message.Successln("β
", "Name received!")
}
// Print horizontal ruler.
// Useful for visually separating the informational messages above from
// actual command output.
// Visible only on verbose mode.
message.HorizontalRuler()
// Finally you often should print some actual command output into standard
// output stream.
fmt.Printf("Hello %s!\n", name)
}
Results of running above code with go run main.go
and various flags:
... or with NO_EMOJI
or <APP_NAME>_NO_EMOJI
environment variables set (to something other than false
or 0
).
... or with NO_COLOR
or <APP_NAME>_NO_COLOR
environment variables set (to something other than false
or 0
).
... or with VERBOSE
or <APP_NAME>_VERBOSE
environment variables set (to something other than false
or 0
).
Unfortunately not all command-line environments are capable of rendering all emojis as they should be rendered. To ensure best possible compatibility with different systems and fonts:
- Use non-gendered emojis
- Use default skintone emojis
- Avoid complex group emojis such as π¨βπ©βπ§βπ§
Sometimes using enescakir/emoji
can make getting the exactly right emoji easier:
emoji.Emoji(emoji.PersonFacepalming.Tone(emoji.Default))
Of course you may use any emoji you wish but note that they may not render as expected in different systems and environments.
You can provide you own io.Writer
via SetMessageTarget
method. This can be useful for testing and for scenarios where you wish to disable the "subprocess friendliness" of writing to tty
directly.
message.SetMessageTarget(os.Stderr)
- Set
VERBOSE=true
environment variable - Set
<APP_NAME>_VERBOSE=true
environment variable - Use
message.SetVerboseMode(true)
method
(setting this tofalse
has no effect if above environment variables present)
- Use
message.SetSiletMode(true)
method
(setting this totrue
has no effect if Verbose Mode is enabled)
- Set
NO_COLOR=true
environment variable - Set
<APP_NAME>_NO_COLOR=true
environment variable - Use
message.SetColorMode(false)
method
(setting this totrue
has no effect if above environment variables present)
- Disabling Color will disable Emoji as well
- Set
NO_EMOJI=true
environment variable - Set
<APP_NAME>_NO_EMOJI=true
environment variable - Use
message.SetEmojiMode(false)
method
(setting this totrue
has no effect if above environment variables present)