💻 PTerm | Pretty Terminal Printer
A modern Go framework to make beautiful CLIs
Show Demo Code
PTerm.sh
|
Installation
|
Getting Started
|
Documentation
|
Examples
|
Q&A
|
Discord
📦 Installation
To make PTerm available in your project, you can run the following command.
Make sure to run this command inside your project, when you're using go modules 😉
go get github.com/pterm/pterm
⭐ Main Features
Feature | Description |
---|
🪀 Easy to use | PTerm emphasizes ease of use, with examples and consistent component design. |
🤹♀️ Cross-Platform | PTerm works on various OS and terminals, including Windows CMD , macOS iTerm2 , and in CI systems like GitHub Actions . |
🧪 Well tested | A high test coverage and 28774 automated tests ensure PTerm's reliability. |
✨ Consistent Colors | PTerm uses the ANSI color scheme for uniformity and supports TrueColor for advanced terminals. |
📚 Component system | PTerm's flexible Printers can be used individually or combined to generate beautiful console output. |
🛠 Configurable | PTerm is ready to use without configuration but allows easy customization for unique terminal output. |
✏ Documentation | Access comprehensive docs on pkg.go.dev and view practical examples in the examples section. |
Printers (Components)
🧪 Examples
area/demo

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
func main() {
pterm.Info.Println("The previous text will stay in place, while the area updates.")
pterm.Print("\n\n")
area, _ := pterm.DefaultArea.WithCenter().Start()
for i := 0; i < 10; i++ {
str, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString(time.Now().Format("15:04:05"))).Srender()
area.Update(str)
time.Sleep(time.Second)
}
area.Stop()
}
area/center

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
area, _ := pterm.DefaultArea.WithCenter().Start()
for i := 0; i < 5; i++ {
area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
time.Sleep(time.Second)
}
area.Stop()
}
area/default

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
area, _ := pterm.DefaultArea.Start()
for i := 0; i < 5; i++ {
area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
time.Sleep(time.Second)
}
area.Stop()
}
area/dynamic-chart

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
area, _ := pterm.DefaultArea.WithFullscreen().WithCenter().Start()
defer area.Stop()
for i := 0; i < 10; i++ {
barchart := pterm.DefaultBarChart.WithBars(dynamicBars(i))
content, _ := barchart.Srender()
area.Update(content)
time.Sleep(500 * time.Millisecond)
}
}
func dynamicBars(i int) pterm.Bars {
return pterm.Bars{
{Label: "A", Value: 10},
{Label: "B", Value: 20 * i},
{Label: "C", Value: 30},
{Label: "D", Value: 40 + i},
}
}
area/fullscreen

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
area, _ := pterm.DefaultArea.WithFullscreen().Start()
for i := 0; i < 5; i++ {
area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
time.Sleep(time.Second)
}
area.Stop()
}
area/fullscreen-center

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
area, _ := pterm.DefaultArea.WithFullscreen().WithCenter().Start()
for i := 0; i < 5; i++ {
area.Update(pterm.Sprintf("Current count: %d\nAreas can update their content dynamically!", i))
time.Sleep(time.Second)
}
area.Stop()
}
barchart/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
bars := []pterm.Bar{
{Label: "Bar 1", Value: 5},
{Label: "Bar 2", Value: 3},
{Label: "Longer Label", Value: 7},
}
pterm.Info.Println("Chart example with positive only values (bars use 100% of chart area)")
pterm.DefaultBarChart.WithBars(bars).Render()
pterm.DefaultBarChart.WithHorizontal().WithBars(bars).Render()
}
barchart/custom-height

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
bars := []pterm.Bar{
{Label: "A", Value: 10},
{Label: "B", Value: 20},
{Label: "C", Value: 30},
{Label: "D", Value: 40},
{Label: "E", Value: 50},
{Label: "F", Value: 40},
{Label: "G", Value: 30},
{Label: "H", Value: 20},
{Label: "I", Value: 10},
}
pterm.DefaultBarChart.WithBars(bars).WithHeight(5).Render()
}
barchart/custom-width

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
barData := []pterm.Bar{
{Label: "A", Value: 10},
{Label: "B", Value: 20},
{Label: "C", Value: 30},
{Label: "D", Value: 40},
{Label: "E", Value: 50},
{Label: "F", Value: 40},
{Label: "G", Value: 30},
{Label: "H", Value: 20},
{Label: "I", Value: 10},
}
pterm.DefaultBarChart.WithBars(barData).WithHorizontal().WithWidth(5).Render()
}
barchart/default

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
bars := []pterm.Bar{
{Label: "A", Value: 10},
{Label: "B", Value: 20},
{Label: "C", Value: 30},
{Label: "D", Value: 40},
{Label: "E", Value: 50},
{Label: "F", Value: 40},
{Label: "G", Value: 30},
{Label: "H", Value: 20},
{Label: "I", Value: 10},
}
pterm.DefaultBarChart.WithBars(bars).Render()
}
barchart/horizontal

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
bars := []pterm.Bar{
{Label: "A", Value: 10},
{Label: "B", Value: 20},
{Label: "C", Value: 30},
{Label: "D", Value: 40},
{Label: "E", Value: 50},
{Label: "F", Value: 40},
{Label: "G", Value: 30},
{Label: "H", Value: 20},
{Label: "I", Value: 10},
}
pterm.DefaultBarChart.WithBars(bars).WithHorizontal().Render()
}
barchart/horizontal-show-value

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
barData := []pterm.Bar{
{Label: "A", Value: 10},
{Label: "B", Value: 20},
{Label: "C", Value: 30},
{Label: "D", Value: 40},
{Label: "E", Value: 50},
{Label: "F", Value: 40},
{Label: "G", Value: 30},
{Label: "H", Value: 20},
{Label: "I", Value: 10},
}
pterm.DefaultBarChart.WithBars(barData).WithHorizontal().WithShowValue().Render()
}
barchart/mixed-values

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
bars := []pterm.Bar{
{Label: "Bar 1", Value: 2},
{Label: "Bar 2", Value: -3},
{Label: "Bar 3", Value: -2},
{Label: "Bar 4", Value: 5},
{Label: "Longer Label", Value: 7},
}
pterm.DefaultSection.Println("Chart example with mixed values (note screen space usage in case when ABSOLUTE values of negative and positive parts are differ too much)")
pterm.DefaultBarChart.WithBars(bars).WithShowValue().Render()
pterm.DefaultBarChart.WithHorizontal().WithBars(bars).WithShowValue().Render()
}
barchart/negative-values

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
negativeBars := pterm.Bars{
{Label: "Bar 1", Value: -5},
{Label: "Bar 2", Value: -3},
{Label: "Longer Label", Value: -7},
}
pterm.Info.Println("Chart example with negative only values (bars use 100% of chart area)")
_ = pterm.DefaultBarChart.WithBars(negativeBars).WithShowValue().Render()
_ = pterm.DefaultBarChart.WithHorizontal().WithBars(negativeBars).WithShowValue().Render()
}
barchart/show-value

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
bars := []pterm.Bar{
{Label: "A", Value: 10},
{Label: "B", Value: 20},
{Label: "C", Value: 30},
{Label: "D", Value: 40},
{Label: "E", Value: 50},
{Label: "F", Value: 40},
{Label: "G", Value: 30},
{Label: "H", Value: 20},
{Label: "I", Value: 10},
}
pterm.DefaultBarChart.WithBars(bars).WithShowValue().Render()
}
basictext/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultBasicText.Println("Default basic text printer.")
pterm.DefaultBasicText.Println("Can be used in any" + pterm.LightMagenta(" TextPrinter ") + "context.")
}
bigtext/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
func main() {
pterm.DefaultBigText.WithLetters(putils.LettersFromString("PTerm")).Render()
pterm.DefaultBigText.WithLetters(
putils.LettersFromStringWithStyle("P", pterm.FgCyan.ToStyle()),
putils.LettersFromStringWithStyle("Term", pterm.FgLightMagenta.ToStyle()),
).Render()
pterm.DefaultBigText.WithLetters(
putils.LettersFromStringWithRGB("PTerm", pterm.NewRGB(255, 215, 0)),
).Render()
}
bigtext/colored

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
func main() {
pterm.DefaultBigText.WithLetters(
putils.LettersFromStringWithStyle("P", pterm.FgCyan.ToStyle()),
putils.LettersFromStringWithStyle("Term", pterm.FgLightMagenta.ToStyle())).
Render()
}
bigtext/default

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
func main() {
var text = "PTerm"
var letters = putils.LettersFromString(text)
pterm.DefaultBigText.WithLetters(letters).Render()
}
box/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.Info.Println("This might not be rendered correctly on GitHub,\nbut it will work in a real terminal.\nThis is because GitHub does not use a monospaced font by default for SVGs")
panel1 := pterm.DefaultBox.Sprint("Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt\nut labore et dolore\nmagna aliqua.")
panel2 := pterm.DefaultBox.WithTitle("title").Sprint("Ut enim ad minim veniam,\nquis nostrud exercitation\nullamco laboris\nnisi ut aliquip\nex ea commodo\nconsequat.")
panel3 := pterm.DefaultBox.WithTitle("bottom center title").WithTitleBottomCenter().Sprint("Duis aute irure\ndolor in reprehenderit\nin voluptate velit esse cillum\ndolore eu fugiat\nnulla pariatur.")
panels, _ := pterm.DefaultPanel.WithPanels(pterm.Panels{
{{Data: panel1}, {Data: panel2}},
{{Data: panel3}},
}).Srender()
pterm.DefaultBox.WithTitle("Lorem Ipsum").WithTitleBottomRight().WithRightPadding(0).WithBottomPadding(0).Println(panels)
}
box/custom-padding

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultBox.WithRightPadding(10).WithLeftPadding(10).WithTopPadding(2).WithBottomPadding(2).Println("Hello, World!")
}
box/default

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultBox.Println("Hello, World!")
}
box/title

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
paddedBox := pterm.DefaultBox.WithLeftPadding(4).WithRightPadding(4).WithTopPadding(1).WithBottomPadding(1)
title := pterm.LightRed("I'm a box!")
box1 := paddedBox.WithTitle(title).Sprint("Hello, World!\n 1")
box2 := paddedBox.WithTitle(title).WithTitleTopCenter().Sprint("Hello, World!\n 2")
box3 := paddedBox.WithTitle(title).WithTitleTopRight().Sprint("Hello, World!\n 3")
box4 := paddedBox.WithTitle(title).WithTitleBottomRight().Sprint("Hello, World!\n 4")
box5 := paddedBox.WithTitle(title).WithTitleBottomCenter().Sprint("Hello, World!\n 5")
box6 := paddedBox.WithTitle(title).WithTitleBottomLeft().Sprint("Hello, World!\n 6")
box7 := paddedBox.WithTitle(title).WithTitleTopLeft().Sprint("Hello, World!\n 7")
pterm.DefaultPanel.WithPanels([][]pterm.Panel{
{{box1}, {box2}, {box3}},
{{box4}, {box5}, {box6}},
{{box7}},
}).Render()
}
bulletlist/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
func main() {
bulletListItems := []pterm.BulletListItem{
{Level: 0, Text: "Level 0"},
{Level: 1, Text: "Level 1"},
{Level: 2, Text: "Level 2"},
}
pterm.DefaultBulletList.WithItems(bulletListItems).Render()
text := `0
1
2
3`
putils.BulletListFromString(text, " ").Render()
}
bulletlist/customized

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
bulletListItems := []pterm.BulletListItem{
{
Level: 0,
Text: "Blue",
TextStyle: pterm.NewStyle(pterm.FgBlue),
BulletStyle: pterm.NewStyle(pterm.FgRed),
},
{
Level: 1,
Text: "Green",
TextStyle: pterm.NewStyle(pterm.FgGreen),
Bullet: "-",
BulletStyle: pterm.NewStyle(pterm.FgLightWhite),
},
{
Level: 2,
Text: "Cyan",
TextStyle: pterm.NewStyle(pterm.FgCyan),
Bullet: ">",
BulletStyle: pterm.NewStyle(pterm.FgYellow),
},
}
pterm.DefaultBulletList.WithItems(bulletListItems).Render()
}
center/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
func main() {
pterm.DefaultCenter.Println("This text is centered!\nIt centers the whole block by default.\nIn that way you can do stuff like this:")
s, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString("PTerm")).Srender()
pterm.DefaultCenter.Println(s)
pterm.DefaultCenter.WithCenterEachLineSeparately().Println("This text is centered!\nBut each line is\ncentered\nseparately")
}
coloring/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultTable.WithData([][]string{
{pterm.FgBlack.Sprint("Black"), pterm.FgRed.Sprint("Red"), pterm.FgGreen.Sprint("Green"), pterm.FgYellow.Sprint("Yellow")},
{"", pterm.FgLightRed.Sprint("Light Red"), pterm.FgLightGreen.Sprint("Light Green"), pterm.FgLightYellow.Sprint("Light Yellow")},
{pterm.BgBlack.Sprint("Black"), pterm.BgRed.Sprint("Red"), pterm.BgGreen.Sprint("Green"), pterm.BgYellow.Sprint("Yellow")},
{"", pterm.BgLightRed.Sprint("Light Red"), pterm.BgLightGreen.Sprint("Light Green"), pterm.BgLightYellow.Sprint("Light Yellow")},
{pterm.FgBlue.Sprint("Blue"), pterm.FgMagenta.Sprint("Magenta"), pterm.FgCyan.Sprint("Cyan"), pterm.FgWhite.Sprint("White")},
{pterm.FgLightBlue.Sprint("Light Blue"), pterm.FgLightMagenta.Sprint("Light Magenta"), pterm.FgLightCyan.Sprint("Light Cyan"), pterm.FgLightWhite.Sprint("Light White")},
{pterm.BgBlue.Sprint("Blue"), pterm.BgMagenta.Sprint("Magenta"), pterm.BgCyan.Sprint("Cyan"), pterm.BgWhite.Sprint("White")},
{pterm.BgLightBlue.Sprint("Light Blue"), pterm.BgLightMagenta.Sprint("Light Magenta"), pterm.BgLightCyan.Sprint("Light Cyan"), pterm.BgLightWhite.Sprint("Light White")},
}).Render()
pterm.Println()
pterm.Println(pterm.Red("Hello, ") + pterm.Green("World") + pterm.Cyan("!"))
pterm.Println(pterm.Red("Even " + pterm.Cyan("nested ") + pterm.Green("colors ") + "are supported!"))
pterm.Println()
style := pterm.NewStyle(pterm.BgRed, pterm.FgLightGreen, pterm.Bold)
style.Println("This text uses a style and is bold and light green with a red background!")
}
coloring/disable-output

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
for i := 0; i < 15; i++ {
switch i {
case 5:
pterm.Info.Println("Disabled Output!")
pterm.DisableOutput()
case 10:
pterm.EnableOutput()
pterm.Info.Println("Enabled Output!")
}
pterm.Printf("Printing something... [%d/%d]\n", i, 15)
}
}
coloring/fade-colors

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
pterm.Info.Println("RGB colors only work in Terminals which support TrueColor.")
startColor := pterm.NewRGB(0, 255, 255)
endColor := pterm.NewRGB(255, 0, 255)
terminalHeight := pterm.GetTerminalHeight()
for i := 0; i < terminalHeight-2; i++ {
fadeFactor := float32(i) / float32(terminalHeight-2)
currentColor := startColor.Fade(0, 1, fadeFactor, endColor)
currentColor.Println("Hello, World!")
}
}
coloring/fade-colors-rgb-style

SHOW SOURCE
package main
import (
"strings"
"github.com/pterm/pterm"
)
func main() {
white := pterm.NewRGB(255, 255, 255)
grey := pterm.NewRGB(128, 128, 128)
black := pterm.NewRGB(0, 0, 0)
red := pterm.NewRGB(255, 0, 0)
purple := pterm.NewRGB(255, 0, 255)
green := pterm.NewRGB(0, 255, 0)
str1 := "RGB colors only work in Terminals which support TrueColor."
str2 := "The background and foreground colors can be customized individually."
str3 := "Styles can also be applied. For example: Bold or Italic."
printFadedString(str1, white, purple, grey, black)
printFadedString(str2, black, purple, red, red)
printStyledString(str3, white, green, red, black)
}
func printFadedString(str string, fgStart, fgEnd, bgStart, bgEnd pterm.RGB) {
strs := strings.Split(str, "")
var result string
for i := 0; i < len(str); i++ {
style := pterm.NewRGBStyle(fgStart.Fade(0, float32(len(str)), float32(i), fgEnd), bgStart.Fade(0, float32(len(str)), float32(i), bgEnd))
result += style.Sprint(strs[i])
}
pterm.Println(result)
}
func printStyledString(str string, fgStart, fgEnd, bgStart, bgEnd pterm.RGB) {
strs := strings.Split(str, "")
var result string
boldStr := strings.Split("Bold", "")
italicStr := strings.Split("Italic", "")
bold, italic := 0, 0
for i := 0; i < len(str); i++ {
style := pterm.NewRGBStyle(fgStart.Fade(0, float32(len(str)), float32(i), fgEnd), bgStart.Fade(0, float32(len(str)), float32(i), bgEnd))
if bold < len(boldStr) && i+len(boldStr)-bold <= len(strs) && strings.Join(strs[i:i+len(boldStr)-bold], "") == strings.Join(boldStr[bold:], "") {
style = style.AddOptions(pterm.Bold)
bold++
} else if italic < len(italicStr) && i+len(italicStr)-italic < len(strs) && strings.Join(strs[i:i+len(italicStr)-italic], "") == strings.Join(italicStr[italic:], "") {
style = style.AddOptions(pterm.Italic)
italic++
}
result += style.Sprint(strs[i])
}
pterm.Println(result)
}
coloring/fade-multiple-colors

SHOW SOURCE
package main
import (
"strings"
"github.com/pterm/pterm"
)
func main() {
startColor := pterm.NewRGB(0, 255, 255)
firstPoint := pterm.NewRGB(255, 0, 255)
secondPoint := pterm.NewRGB(255, 0, 0)
thirdPoint := pterm.NewRGB(0, 255, 0)
endColor := pterm.NewRGB(255, 255, 255)
str := "RGB colors only work in Terminals which support TrueColor."
strs := strings.Split(str, "")
var fadeInfo string
for i := 0; i < len(str); i++ {
fadeInfo += startColor.Fade(0, float32(len(str)), float32(i), firstPoint).Sprint(strs[i])
}
pterm.Info.Println(fadeInfo)
terminalHeight := pterm.GetTerminalHeight()
for i := 0; i < terminalHeight-2; i++ {
startColor.Fade(0, float32(terminalHeight-2), float32(i), firstPoint, secondPoint, thirdPoint, endColor).Println("Hello, World!")
}
}
coloring/override-default-printers

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.Error.Println("This is the default Error")
pterm.Error.Prefix = pterm.Prefix{Text: "OVERRIDE", Style: pterm.NewStyle(pterm.BgCyan, pterm.FgRed)}
pterm.Error.Println("This is the default Error after the prefix was overridden")
}
coloring/print-color-rgb

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.NewRGB(178, 44, 199).Println("This text is printed with a custom RGB!")
pterm.NewRGB(15, 199, 209).Println("This text is printed with a custom RGB!")
pterm.NewRGB(201, 144, 30, true).Println("This text is printed with a custom RGB background!")
}
coloring/print-color-rgb-style

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
foregroundRGB := pterm.RGB{R: 187, G: 80, B: 0}
backgroundRGB := pterm.RGB{R: 0, G: 50, B: 123}
rgbStyle := pterm.NewRGBStyle(foregroundRGB, backgroundRGB)
rgbStyle.Println("This text is not styled.")
rgbStyle.AddOptions(pterm.Bold).Println("This text is bold.")
rgbStyle.AddOptions(pterm.Italic).Println("This text is italic.")
}
demo/demo

SHOW SOURCE
package main
import (
"flag"
"math/rand"
"reflect"
"strconv"
"strings"
"time"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
var speedup = flag.Bool("speedup", false, "Speed up the demo")
var skipIntro = flag.Bool("skip-intro", false, "Skips the intro")
var second = time.Second
var pseudoProgramList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
"pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
func main() {
setup()
if !*skipIntro {
introScreen()
clear()
}
showcase("Structured Logging", 5, func() {
logger := pterm.DefaultLogger.
WithLevel(pterm.LogLevelTrace)
logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
time.Sleep(time.Second * 3)
interstingStuff := map[string]any{
"when were crayons invented": "1903",
"what is the meaning of life": 42,
"is this interesting": true,
}
logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
time.Sleep(time.Second * 3)
logger.Info("That was actually interesting", logger.Args("such", "wow"))
time.Sleep(time.Second * 3)
logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
time.Sleep(time.Second * 3)
logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
time.Sleep(time.Second * 3)
logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
})
showcase("Progress bar", 2, func() {
pb, _ := pterm.DefaultProgressbar.WithTotal(len(pseudoProgramList)).WithTitle("Installing stuff").Start()
for i := 0; i < pb.Total; i++ {
pb.UpdateTitle("Installing " + pseudoProgramList[i])
if pseudoProgramList[i] == "pseudo-minecraft" {
pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
} else {
pterm.Success.Println("Installing " + pseudoProgramList[i])
}
pb.Increment()
time.Sleep(second / 2)
}
pb.Stop()
})
showcase("Spinner", 2, func() {
list := pseudoProgramList[7:]
spinner, _ := pterm.DefaultSpinner.Start("Installing stuff")
for i := 0; i < len(list); i++ {
spinner.UpdateText("Installing " + list[i])
if list[i] == "pseudo-minecraft" {
pterm.Warning.Println("Could not install pseudo-minecraft\nThe company policy forbids games.")
} else {
pterm.Success.Println("Installing " + list[i])
}
time.Sleep(second)
}
spinner.Success()
})
showcase("Live Output", 2, func() {
pterm.Info.Println("You can use an Area to display changing output:")
pterm.Println()
area, _ := pterm.DefaultArea.WithCenter().Start()
for i := 0; i < 10; i++ {
str, _ := pterm.DefaultBigText.WithLetters(putils.LettersFromString(time.Now().Format("15:04:05"))).Srender()
area.Update(str)
time.Sleep(time.Second)
}
area.Stop()
})
showcase("Tables", 4, func() {
for i := 0; i < 3; i++ {
pterm.Println()
}
td := [][]string{
{"Library", "Description"},
{"PTerm", "Make beautiful CLIs"},
{"Testza", "Programmer friendly test framework"},
{"Cursor", "Move the cursor around the terminal"},
}
table, _ := pterm.DefaultTable.WithHasHeader().WithData(td).Srender()
boxedTable, _ := pterm.DefaultTable.WithHasHeader().WithData(td).WithBoxed().Srender()
pterm.DefaultCenter.Println(table)
pterm.DefaultCenter.Println(boxedTable)
})
showcase("TrueColor Support", 7, func() {
from := pterm.NewRGB(0, 255, 255)
to := pterm.NewRGB(255, 0, 255)
str := "If your terminal has TrueColor support, you can use RGB colors!\nYou can even fade them :)\n\nLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
strs := strings.Split(str, "")
var fadeInfo string
for i := 0; i < len(str); i++ {
fadeInfo += from.Fade(0, float32(len(str)), float32(i), to).Sprint(strs[i])
}
pterm.DefaultCenter.WithCenterEachLineSeparately().Println(fadeInfo)
})
showcase("Fully Customizable", 2, func() {
for i := 0; i < 4; i++ {
pterm.Println()
}
text := "All printers are fully customizable!"
area := pterm.DefaultArea.WithCenter()
area.Update(pterm.DefaultBox.Sprintln(text))
time.Sleep(second)
area.Update(pterm.DefaultBox.WithTopPadding(1).Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopLeft().Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopCenter().Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleTopRight().Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomRight().Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomCenter().Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithTitle("Some title!").WithTitleBottomLeft().Sprintln(text))
time.Sleep(second / 3)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgCyan)).Sprintln(text))
time.Sleep(second / 5)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgRed)).Sprintln(text))
time.Sleep(second / 5)
area.Update(pterm.DefaultBox.WithTopPadding(1).WithBottomPadding(1).WithLeftPadding(1).WithRightPadding(1).WithBoxStyle(pterm.NewStyle(pterm.FgGreen)).Sprintln(text))
time.Sleep(second / 5)
area.Update(pterm.DefaultBox.WithTopPadding(1).
WithBottomPadding(1).
WithLeftPadding(1).
WithRightPadding(1).
WithHorizontalString("═").
WithVerticalString("║").
WithBottomLeftCornerString("╗").
WithBottomRightCornerString("╔").
WithTopLeftCornerString("╝").
WithTopRightCornerString("╚").
Sprintln(text))
area.Stop()
})
showcase("Themes", 2, func() {
pterm.Info.Println("You can change the color theme of PTerm easily to fit your needs!\nThis is the default one:")
time.Sleep(second / 2)
v := reflect.ValueOf(pterm.ThemeDefault)
typeOfS := v.Type()
if typeOfS == reflect.TypeOf(pterm.Theme{}) {
for i := 0; i < v.NumField(); i++ {
field, ok := v.Field(i).Interface().(pterm.Style)
if ok {
field.Println(typeOfS.Field(i).Name)
}
time.Sleep(time.Millisecond * 250)
}
}
})
showcase("And much more!", 3, func() {
for i := 0; i < 4; i++ {
pterm.Println()
}
box := pterm.DefaultBox.
WithBottomPadding(1).
WithTopPadding(1).
WithLeftPadding(3).
WithRightPadding(3).
Sprintf("Have fun exploring %s!", pterm.Cyan("PTerm"))
pterm.DefaultCenter.Println(box)
})
}
func setup() {
flag.Parse()
if *speedup {
second = time.Millisecond * 200
}
}
func introScreen() {
ptermLogo, _ := pterm.DefaultBigText.WithLetters(
putils.LettersFromStringWithStyle("P", pterm.NewStyle(pterm.FgLightCyan)),
putils.LettersFromStringWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
Srender()
pterm.DefaultCenter.Print(ptermLogo)
pterm.DefaultCenter.Print(pterm.DefaultHeader.WithFullWidth().WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Sprint("PTDP - PTerm Demo Program"))
pterm.Info.Println("This animation was generated with the latest version of PTerm!" +
"\nPTerm works on nearly every terminal and operating system." +
"\nIt's super easy to use!" +
"\nIf you want, you can customize everything :)" +
"\nYou can see the code of this demo in the " + pterm.LightMagenta("./_examples/demo") + " directory." +
"\n" +
"\nThis demo was updated at: " + pterm.Green(time.Now().Format("02 Jan 2006 - 15:04:05 MST")))
pterm.Println()
introSpinner, _ := pterm.DefaultSpinner.WithShowTimer(false).WithRemoveWhenDone(true).Start("Waiting for 15 seconds...")
time.Sleep(second)
for i := 14; i > 0; i-- {
if i > 1 {
introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " seconds...")
} else {
introSpinner.UpdateText("Waiting for " + strconv.Itoa(i) + " second...")
}
time.Sleep(second)
}
introSpinner.Stop()
}
func clear() {
print("\033[H\033[2J")
}
func showcase(title string, seconds int, content func()) {
pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithFullWidth().Println(title)
pterm.Println()
time.Sleep(second / 2)
content()
time.Sleep(second * time.Duration(seconds))
print("\033[H\033[2J")
}
func randomInt(min, max int) int {
rand.Seed(time.Now().UnixNano())
return rand.Intn(max-min+1) + min
}

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultHeader.Println("This is the default header!")
pterm.Println()
pterm.DefaultHeader.WithFullWidth().Println("This is a full-width header.")
}

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultHeader.WithMargin(15).WithBackgroundStyle(pterm.NewStyle(pterm.BgCyan)).WithTextStyle(pterm.NewStyle(pterm.FgBlack)).Println("This is a custom header!")
newHeader := pterm.HeaderPrinter{
TextStyle: pterm.NewStyle(pterm.FgBlack),
BackgroundStyle: pterm.NewStyle(pterm.BgRed),
Margin: 20,
}
newHeader.Println("This is a custom header!")
}
heatmap/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
data := [][]float32{
{0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
{0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
{0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
{0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
{0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
}
headerData := pterm.HeatmapAxis{
XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
YAxis: []string{"1", "2", "3", "4", "5"},
}
pterm.DefaultHeatmap.WithAxisData(headerData).WithData(data).WithEnableRGB().Render()
}
heatmap/custom_colors

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
data := [][]float32{
{0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
{0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
{0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
{0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
{0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
}
headerData := pterm.HeatmapAxis{
XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
YAxis: []string{"1", "2", "3", "4", "5"},
}
pterm.Info.Println("The following table has no rgb (supported by every terminal), no axis data and a legend.")
pterm.Println()
pterm.DefaultHeatmap.
WithData(data).
WithBoxed(false).
WithAxisData(headerData).
WithLegend(false).
WithColors(pterm.BgBlue, pterm.BgRed, pterm.BgGreen, pterm.BgYellow).
WithLegend().
Render()
}
heatmap/custom_legend

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
data := [][]float32{
{0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
{0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
{0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
{0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
{0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
}
headerData := pterm.HeatmapAxis{
XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
YAxis: []string{"1", "2", "3", "4", "5"},
}
pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a custom legend.")
pterm.Println()
pterm.DefaultHeatmap.
WithData(data).
WithBoxed(false).
WithAxisData(headerData).
WithEnableRGB().
WithLegendLabel("custom").
WithLegendOnlyColoredCells().
Render()
}
heatmap/custom_rgb

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
data := [][]float32{
{0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
{0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
{0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
{0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
{0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
}
axisLabels := pterm.HeatmapAxis{
XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
YAxis: []string{"1", "2", "3", "4", "5"},
}
pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a legend.")
pterm.Println()
rgbRange := []pterm.RGB{
pterm.NewRGB(0, 0, 255),
pterm.NewRGB(255, 0, 0),
pterm.NewRGB(0, 255, 0),
pterm.NewRGB(255, 255, 0),
}
pterm.DefaultHeatmap.
WithData(data).
WithBoxed(false).
WithAxisData(axisLabels).
WithEnableRGB().
WithRGBRange(rgbRange...).
Render()
}
heatmap/no_grid

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
data := [][]float32{
{0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
{0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
{0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
{0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
{0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
}
axisData := pterm.HeatmapAxis{
XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
YAxis: []string{"1", "2", "3", "4", "5"},
}
pterm.Info.Println("The following table has rgb (not supported by every terminal), axis data and a legend.")
pterm.Println()
pterm.DefaultHeatmap.WithData(data).WithBoxed(false).WithAxisData(axisData).WithEnableRGB().WithLegend().WithGrid(false).Render()
}
heatmap/separated

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
data := [][]float32{
{0.9, 0.2, -0.7, 0.4, -0.5, 0.6, -0.3, 0.8, -0.1, -1.0, 0.1, -0.8, 0.3},
{0.2, -0.7, -0.5, -0.3, -0.1, 0.1, 0.3, 0.5, 0.9, -0.9, -0.7, -0.5, -0.3},
{0.4, 0.4, -0.3, -1.0, 0.3, -0.2, -0.9, 0.5, -0.3, -1.0, 0.6, -0.2, -0.9},
{0.9, -0.5, -0.1, 0.3, 1, -0.7, -0.3, 0.1, 0.7, -0.9, -0.5, 0.2, 0.6},
{0.5, 0.6, 0.1, -0.2, -0.7, 0.8, 0.6, 0.1, -0.5, -0.7, 0.7, 0.3, 0.0},
}
headerData := pterm.HeatmapAxis{
XAxis: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"},
YAxis: []string{"1", "2", "3", "4", "5"},
}
pterm.Info.Println("The following table has no rgb (supported by every terminal), no axis data and no legend.")
pterm.Println()
pterm.DefaultHeatmap.WithData(data).WithBoxed(false).WithAxisData(headerData).WithLegend(false).Render()
}
interactive_confirm/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
result, _ := pterm.DefaultInteractiveConfirm.Show()
pterm.Println()
pterm.Info.Printfln("You answered: %s", boolToText(result))
}
func boolToText(b bool) string {
if b {
return pterm.Green("Yes")
}
return pterm.Red("No")
}
interactive_continue/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
prompt := pterm.DefaultInteractiveContinue
result, _ := prompt.Show()
pterm.Println()
pterm.Info.Printfln("You answered: %s", result)
}
interactive_multiselect/demo

SHOW SOURCE
package main
import (
"fmt"
"github.com/pterm/pterm"
)
func main() {
var options []string
for i := 0; i < 100; i++ {
options = append(options, fmt.Sprintf("Option %d", i))
}
for i := 0; i < 5; i++ {
options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
}
selectedOptions, _ := pterm.DefaultInteractiveMultiselect.WithOptions(options).Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
interactive_multiselect/custom-checkmarks

SHOW SOURCE
package main
import (
"fmt"
"github.com/pterm/pterm"
)
func main() {
var options []string
for i := 0; i < 5; i++ {
options = append(options, fmt.Sprintf("Option %d", i))
}
printer := pterm.DefaultInteractiveMultiselect.
WithOptions(options).
WithFilter(false).
WithCheckmark(&pterm.Checkmark{Checked: pterm.Green("+"), Unchecked: pterm.Red("-")})
selectedOptions, _ := printer.Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
interactive_multiselect/custom-keys

SHOW SOURCE
package main
import (
"atomicgo.dev/keyboard/keys"
"fmt"
"github.com/pterm/pterm"
)
func main() {
var options []string
for i := 0; i < 5; i++ {
options = append(options, fmt.Sprintf("Option %d", i))
}
printer := pterm.DefaultInteractiveMultiselect.
WithOptions(options).
WithFilter(false).
WithKeyConfirm(keys.Enter).
WithKeySelect(keys.Space)
selectedOptions, _ := printer.Show()
pterm.Info.Printfln("Selected options: %s", pterm.Green(selectedOptions))
}
interactive_select/demo

SHOW SOURCE
package main
import (
"fmt"
"github.com/pterm/pterm"
)
func main() {
var options []string
for i := 0; i < 100; i++ {
options = append(options, fmt.Sprintf("Option %d", i))
}
for i := 0; i < 5; i++ {
options = append(options, fmt.Sprintf("You can use fuzzy searching (%d)", i))
}
selectedOption, _ := pterm.DefaultInteractiveSelect.WithOptions(options).Show()
pterm.Info.Printfln("Selected option: %s", pterm.Green(selectedOption))
}
interactive_textinput/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
result, _ := pterm.DefaultInteractiveTextInput.Show()
pterm.Println()
pterm.Info.Printfln("You answered: %s", result)
}
interactive_textinput/default-value

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
result, _ := pterm.DefaultInteractiveTextInput.WithDefaultValue("Some default value").Show()
pterm.Println()
pterm.Info.Printfln("You answered: %s", result)
}
interactive_textinput/multi-line

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
textInput := pterm.DefaultInteractiveTextInput.WithMultiLine()
result, _ := textInput.Show()
pterm.Println()
pterm.Info.Printfln("You answered: %s", result)
}
interactive_textinput/password

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
passwordInput := pterm.DefaultInteractiveTextInput.WithMask("*")
result, _ := passwordInput.Show("Enter your password")
logger := pterm.DefaultLogger
logger.Info("Password received", logger.Args("password", result))
}
logger/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"time"
)
func main() {
logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
sleep()
interstingStuff := map[string]any{
"when were crayons invented": "1903",
"what is the meaning of life": 42,
"is this interesting": true,
}
logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
sleep()
logger.Info("That was actually interesting", logger.Args("such", "wow"))
sleep()
logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
sleep()
logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
sleep()
logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
sleep()
logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
}
func sleep() {
time.Sleep(time.Second * 3)
}
logger/custom-key-styles

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
priorityStyle := map[string]pterm.Style{
"priority": *pterm.NewStyle(pterm.FgRed),
}
logger = logger.WithKeyStyles(priorityStyle)
logger.Info("The priority key should now be red", logger.Args("priority", "low", "foo", "bar"))
fooStyle := *pterm.NewStyle(pterm.FgBlue)
logger.AppendKeyStyle("foo", fooStyle)
logger.Info("The foo key should now be blue", logger.Args("priority", "low", "foo", "bar"))
}
logger/default

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"time"
)
func main() {
logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace)
logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
interstingStuff := map[string]any{
"when were crayons invented": "1903",
"what is the meaning of life": 42,
"is this interesting": true,
}
logger.Debug("This might be interesting", logger.ArgsFromMap(interstingStuff))
logger.Info("That was actually interesting", logger.Args("such", "wow"))
logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
time.Sleep(time.Second * 2)
logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
}
logger/json

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace).WithFormatter(pterm.LogFormatterJSON)
logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
interestingStuff := map[string]any{
"when were crayons invented": "1903",
"what is the meaning of life": 42,
"is this interesting": true,
}
logger.Debug("This might be interesting", logger.ArgsFromMap(interestingStuff))
logger.Info("That was actually interesting", logger.Args("such", "wow"))
logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
}
logger/with-caller

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
logger := pterm.DefaultLogger.WithLevel(pterm.LogLevelTrace).WithCaller()
logger.Trace("Doing not so important stuff", logger.Args("priority", "super low"))
interestingStuff := map[string]any{
"when were crayons invented": "1903",
"what is the meaning of life": 42,
"is this interesting": true,
}
logger.Debug("This might be interesting", logger.ArgsFromMap(interestingStuff))
logger.Info("That was actually interesting", logger.Args("such", "wow"))
logger.Warn("Oh no, I see an error coming to us!", logger.Args("speed", 88, "measures", "mph"))
logger.Error("Damn, here it is!", logger.Args("error", "something went wrong"))
logger.Info("But what's really cool is, that you can print very long logs, and PTerm will automatically wrap them for you! Say goodbye to text, that has weird line breaks!", logger.Args("very", "long"))
logger.Fatal("Oh no, this process is getting killed!", logger.Args("fatal", true))
}
multiple-live-printers/demo

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
multi := pterm.DefaultMultiPrinter
spinner1, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 1")
spinner2, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 2")
pb1, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 1")
pb2, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 2")
pb3, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 3")
pb4, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 4")
pb5, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 5")
multi.Start()
for i := 1; i <= 100; i++ {
pb1.Increment()
if i%2 == 0 {
pb2.Add(3)
}
if i%5 == 0 {
pb3.Increment()
}
if i%10 == 0 {
pb4.Increment()
}
if i%3 == 0 {
pb5.Increment()
}
if i%50 == 0 {
spinner1.Success("Spinner 1 is done!")
}
if i%60 == 0 {
spinner2.Fail("Spinner 2 failed!")
}
time.Sleep(time.Millisecond * 50)
}
multi.Stop()
}
panel/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
panels := pterm.Panels{
{
{Data: "This is the first panel"},
{Data: pterm.DefaultHeader.Sprint("Hello, World!")},
{Data: "This\npanel\ncontains\nmultiple\nlines"},
},
{
{Data: pterm.Red("This is another\npanel line")},
{Data: "This is the second panel\nwith a new line"},
},
}
_ = pterm.DefaultPanel.WithPanels(panels).WithPadding(5).Render()
}
paragraph/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultParagraph.Println("This is the default paragraph printer. As you can see, no words are separated, " +
"but the text is split at the spaces. This is useful for continuous text of all kinds. You can manually change the line width if you want to." +
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
pterm.Println()
pterm.Println("This text is written with the default Println() function. No intelligent splitting here." +
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam")
}
paragraph/customized

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
longText := "This is a custom paragraph printer. As you can see, no words are separated, " +
"but the text is split at the spaces. This is useful for continuous text of all kinds. You can manually change the line width if you want to." +
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam"
pterm.DefaultParagraph.WithMaxWidth(60).Println(longText)
pterm.Println()
longTextWithoutParagraph := "This text is written with the default Println() function. No intelligent splitting here." +
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam"
pterm.Println(longTextWithoutParagraph)
}
prefix/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.EnableDebugMessages()
pterm.Debug.Println("Hello, World!")
pterm.Info.Println("Hello, World!")
pterm.Success.Println("Hello, World!")
pterm.Warning.Println("Hello, World!")
pterm.Error.Println("Errors show the filename and linenumber inside the terminal!")
pterm.Info.WithShowLineNumber().Println("Other PrefixPrinters can do that too!")
pterm.Fatal.WithFatal(false).Println("Hello, World!")
}
progressbar/demo

SHOW SOURCE
package main
import (
"strings"
"time"
"github.com/pterm/pterm"
)
var fakeInstallList = strings.Split("pseudo-excel pseudo-photoshop pseudo-chrome pseudo-outlook pseudo-explorer "+
"pseudo-dops pseudo-git pseudo-vsc pseudo-intellij pseudo-minecraft pseudo-scoop pseudo-chocolatey", " ")
func main() {
p, _ := pterm.DefaultProgressbar.WithTotal(len(fakeInstallList)).WithTitle("Downloading stuff").Start()
for i := 0; i < p.Total; i++ {
if i == 6 {
time.Sleep(time.Second * 3)
}
p.UpdateTitle("Downloading " + fakeInstallList[i])
pterm.Success.Println("Downloading " + fakeInstallList[i])
p.Increment()
time.Sleep(time.Millisecond * 350)
}
}
progressbar/multiple

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
multi := pterm.DefaultMultiPrinter
pb1, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 1")
pb2, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 2")
pb3, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 3")
pb4, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 4")
pb5, _ := pterm.DefaultProgressbar.WithTotal(100).WithWriter(multi.NewWriter()).Start("Progressbar 5")
multi.Start()
for i := 1; i <= 100; i++ {
pb1.Increment()
if i%2 == 0 {
pb2.Add(3)
}
if i%5 == 0 {
pb3.Increment()
}
if i%10 == 0 {
pb4.Increment()
}
if i%3 == 0 {
pb5.Increment()
}
time.Sleep(time.Millisecond * 50)
}
multi.Stop()
}
section/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
pterm.DefaultSection.Println("This is a section!")
pterm.Info.Println("And here is some text.\nThis text could be anything.\nBasically it's just a placeholder")
pterm.DefaultSection.WithLevel(2).Println("This is another section!")
pterm.Info.Println("And this is\nmore placeholder text")
}
slog/demo

SHOW SOURCE
package main
import (
"log/slog"
"github.com/pterm/pterm"
)
func main() {
handler := pterm.NewSlogHandler(&pterm.DefaultLogger)
logger := slog.New(handler)
logger.Debug("This is a debug message that won't show")
pterm.DefaultLogger.Level = pterm.LogLevelDebug
logger.Debug("This is a debug message", "changedLevel", true)
logger.Info("This is an info message")
logger.Warn("This is a warning message")
logger.Error("This is an error message")
}
spinner/demo

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
spinnerInfo, _ := pterm.DefaultSpinner.Start("Some informational action...")
time.Sleep(time.Second * 2)
spinnerInfo.Info()
spinnerSuccess, _ := pterm.DefaultSpinner.Start("Doing something important... (will succeed)")
time.Sleep(time.Second * 2)
spinnerSuccess.Success()
spinnerWarning, _ := pterm.DefaultSpinner.Start("Doing something important... (will warn)")
time.Sleep(time.Second * 2)
spinnerWarning.Warning()
spinnerFail, _ := pterm.DefaultSpinner.Start("Doing something important... (will fail)")
time.Sleep(time.Second * 2)
spinnerFail.Fail()
spinnerNochange, _ := pterm.DefaultSpinner.Start("Checking something important... (will result in no change)")
spinnerNochange.InfoPrinter = &pterm.PrefixPrinter{
MessageStyle: &pterm.Style{pterm.FgLightBlue},
Prefix: pterm.Prefix{
Style: &pterm.Style{pterm.FgBlack, pterm.BgLightBlue},
Text: " NOCHG ",
},
}
time.Sleep(time.Second * 2)
spinnerNochange.Info("No change were required")
spinnerLiveText, _ := pterm.DefaultSpinner.Start("Doing a lot of stuff...")
time.Sleep(time.Second)
spinnerLiveText.UpdateText("It's really much")
time.Sleep(time.Second)
spinnerLiveText.UpdateText("We're nearly done!")
time.Sleep(time.Second)
spinnerLiveText.Success("Finally!")
}
spinner/multiple

SHOW SOURCE
package main
import (
"time"
"github.com/pterm/pterm"
)
func main() {
multi := pterm.DefaultMultiPrinter
spinner1, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 1")
spinner2, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 2")
spinner3, _ := pterm.DefaultSpinner.WithWriter(multi.NewWriter()).Start("Spinner 3")
multi.Start()
time.Sleep(time.Millisecond * 1000)
spinner1.Success("Spinner 1 is done!")
time.Sleep(time.Millisecond * 750)
spinner2.Fail("Spinner 2 failed!")
time.Sleep(time.Millisecond * 500)
spinner3.Warning("Spinner 3 has a warning!")
multi.Stop()
}
style/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
primary := pterm.NewStyle(pterm.FgLightCyan, pterm.BgGray, pterm.Bold)
secondary := pterm.NewStyle(pterm.FgLightGreen, pterm.BgWhite, pterm.Italic)
primary.Println("Hello, World!")
secondary.Println("Hello, World!")
}
table/demo

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
tableData1 := pterm.TableData{
{"Firstname", "Lastname", "Email", "Note"},
{"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
{"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
{"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
{"张", "小宝", "zhang@example.com", ""},
}
pterm.DefaultTable.WithHasHeader().WithData(tableData1).Render()
pterm.Println()
tableData2 := pterm.TableData{
{"Firstname", "Lastname", "Email"},
{"Paul\n\nNewline", "Dean", "augue@velitAliquam.co.uk"},
{"Callie", "Mckay", "nunc.sed@est.com\nNewline"},
{"Libby", "Camacho", "lobortis@semper.com"},
{"张", "小宝", "zhang@example.com"},
}
pterm.DefaultTable.WithHasHeader().WithData(tableData2).Render()
}
table/alternate-row-style

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
alternateStyle := pterm.NewStyle(pterm.BgDarkGray)
tableData := pterm.TableData{
{"Firstname", "Lastname", "Email", "Note"},
{"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
{"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
{"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
{"张", "小宝", "zhang@example.com", ""},
}
pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).WithAlternateRowStyle(alternateStyle).Render()
}
table/boxed

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
tableData := pterm.TableData{
{"Firstname", "Lastname", "Email", "Note"},
{"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
{"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
{"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
{"张", "小宝", "zhang@example.com", ""},
}
pterm.DefaultTable.WithHasHeader().WithBoxed().WithData(tableData).Render()
}
table/multiple-lines

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
data := pterm.TableData{
{"Firstname", "Lastname", "Email"},
{"Paul\n\nNewline", "Dean", "augue@velitAliquam.co.uk"},
{"Callie", "Mckay", "nunc.sed@est.com\nNewline"},
{"Libby", "Camacho", "lobortis@semper.com"},
{"张", "小宝", "zhang@example.com"},
}
pterm.DefaultTable.WithHasHeader().WithRowSeparator("-").WithHeaderRowSeparator("-").WithData(data).Render()
}
table/right-alignment

SHOW SOURCE
package main
import "github.com/pterm/pterm"
func main() {
tableData := pterm.TableData{
{"Firstname", "Lastname", "Email", "Note"},
{"Paul", "Dean", "augue@velitAliquam.co.uk", ""},
{"Callie", "Mckay", "nunc.sed@est.com", "这是一个测试, haha!"},
{"Libby", "Camacho", "lobortis@semper.com", "just a test, hey!"},
{"张", "小宝", "zhang@example.com", ""},
}
pterm.DefaultTable.WithHasHeader().WithRightAlignment().WithData(tableData).Render()
}
theme/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"reflect"
"time"
)
func main() {
pterm.Info.Println("These are the default theme styles.\nYou can modify them easily to your personal preference,\nor create new themes from scratch :)")
pterm.Println()
v := reflect.ValueOf(pterm.ThemeDefault)
typeOfS := v.Type()
if typeOfS == reflect.TypeOf(pterm.Theme{}) {
for i := 0; i < v.NumField(); i++ {
field, ok := v.Field(i).Interface().(pterm.Style)
if ok {
field.Println(typeOfS.Field(i).Name)
}
time.Sleep(time.Millisecond * 250)
}
}
}
tree/demo

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
)
func main() {
tree := pterm.TreeNode{
Text: "Top node",
Children: []pterm.TreeNode{{
Text: "Child node",
Children: []pterm.TreeNode{
{Text: "Grandchild node"},
{Text: "Grandchild node"},
{Text: "Grandchild node"},
},
}},
}
pterm.DefaultTree.WithRoot(tree).Render()
}
tree/from-leveled-list

SHOW SOURCE
package main
import (
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
)
func main() {
leveledList := pterm.LeveledList{
{Level: 0, Text: "C:"},
{Level: 1, Text: "Users"},
{Level: 1, Text: "Windows"},
{Level: 1, Text: "Programs"},
{Level: 1, Text: "Programs(x86)"},
{Level: 1, Text: "dev"},
{Level: 0, Text: "D:"},
{Level: 0, Text: "E:"},
{Level: 1, Text: "Movies"},
{Level: 1, Text: "Music"},
{Level: 2, Text: "LinkinPark"},
{Level: 1, Text: "Games"},
{Level: 2, Text: "Shooter"},
{Level: 3, Text: "CallOfDuty"},
{Level: 3, Text: "CS:GO"},
{Level: 3, Text: "Battlefield"},
{Level: 4, Text: "Battlefield 1"},
{Level: 4, Text: "Battlefield 2"},
{Level: 0, Text: "F:"},
{Level: 1, Text: "dev"},
{Level: 2, Text: "dops"},
{Level: 2, Text: "PTerm"},
}
root := putils.TreeFromLeveledList(leveledList)
root.Text = "Computer"
pterm.DefaultTree.WithRoot(root).Render()
}
GitHub @pterm ·
Author @MarvinJWendt
| PTerm.sh