Repository: pterm/pterm
Pull request #75 (2020-10-22 19:47:37)

feat: add `BigTextPrinter`
### Description
Describe your work here.

### Scope
> What is affected by this pull request?

- [ ] Bug Fix
- [x] New Feature
- [ ] Documentation
- [ ] Other


### To-Do Checklist
- [x] I tested my changes
- [x] I have commented every method that I created/changed
- [x] I updated the examples to fit with my changes
- [x] I have added tests for my newly created methods


codecov[bot]: # [Codecov](https://codecov.io/gh/pterm/pterm/pull/75?src=pr&el=h1) Report
> Merging [#75](https://codecov.io/gh/pterm/pterm/pull/75?src=pr&el=desc) into [master](https://codecov.io/gh/pterm/pterm/commit/4bb39c55adc08a3fc6be239fe5451419cc413cb0?el=desc) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/pterm/pterm/pull/75/graphs/tree.svg?width=650&height=150&src=pr&token=C3EX231V76)](https://codecov.io/gh/pterm/pterm/pull/75?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##            master       #75   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           14        15    +1     
  Lines          501       544   +43     
=========================================
+ Hits           501       544   +43     
```


| [Impacted Files](https://codecov.io/gh/pterm/pterm/pull/75?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [bulletlist\_printer.go](https://codecov.io/gh/pterm/pterm/pull/75/diff?src=pr&el=tree#diff-YnVsbGV0bGlzdF9wcmludGVyLmdv) | `100.00% <ø> (ø)` | |
| [header\_printer.go](https://codecov.io/gh/pterm/pterm/pull/75/diff?src=pr&el=tree#diff-aGVhZGVyX3ByaW50ZXIuZ28=) | `100.00% <ø> (ø)` | |
| [bigtext\_printer.go](https://codecov.io/gh/pterm/pterm/pull/75/diff?src=pr&el=tree#diff-YmlndGV4dF9wcmludGVyLmdv) | `100.00% <100.00%> (ø)` | |
| [theme.go](https://codecov.io/gh/pterm/pterm/pull/75/diff?src=pr&el=tree#diff-dGhlbWUuZ28=) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pterm/pterm/pull/75?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pterm/pterm/pull/75?src=pr&el=footer). Last update [4bb39c5...df3a216](https://codecov.io/gh/pterm/pterm/pull/75?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2ff01cec..817eaea9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -35,24 +35,27 @@ func (p TemplatePrinter) Sprintf(format string, a ...interface{}) string {
 // Print formats using the default formats for its operands and writes to standard output.
 // Spaces are added between operands when neither is a string.
 // It returns the number of bytes written and any write error encountered.
-func (p TemplatePrinter) Print(a ...interface{}) TextPrinter {
+func (p TemplatePrinter) Print(a ...interface{}) *TextPrinter {
 	Print(p.Sprint(a...))
-	return &p
+	tp := TextPrinter(p)
+	return &tp
 }
 
 // Println formats using the default formats for its operands and writes to standard output.
 // Spaces are always added between operands and a newline is appended.
 // It returns the number of bytes written and any write error encountered.
-func (p TemplatePrinter) Println(a ...interface{}) TextPrinter {
+func (p TemplatePrinter) Println(a ...interface{}) *TextPrinter {
 	Println(p.Sprint(a...))
-	return &p
+    tp := TextPrinter(p)
+    return &tp
 }
 
 // Printf formats according to a format specifier and writes to standard output.
 // It returns the number of bytes written and any write error encountered.
-func (p TemplatePrinter) Printf(format string, a ...interface{}) TextPrinter {
+func (p TemplatePrinter) Printf(format string, a ...interface{}) *TextPrinter {
 	Print(p.Sprintf(format, a...))
-	return &p
+	tp := TextPrinter(p)
+	return &tp
 }
 ```
 
@@ -60,13 +63,13 @@ func (p TemplatePrinter) Printf(format string, a ...interface{}) TextPrinter {
 
 ```go
 // Srender renders the Template as a string.
-func (p Table) Srender() string {
+func (p Template) Srender() string {
 	
 }
 
 // Render prints the Template to the terminal.
-func (p Table) Render() {
-
+func (p BigTextPrinter) Render() {
+	Println(p.Srender())
 }
 ```
 
@@ -74,7 +77,7 @@ func (p Table) Render() {
 
 ```go
 // Start the spinner.
-func (s Spinner) Start(text ...interface{}) *Template { // TODO: Replace Template with actual printer.
+func (s Spinner) Start(text...interface{}) *Template { // TODO: Replace Template with actual printer.
 	// TODO: start logic
 	return &s
 }
@@ -188,4 +191,4 @@ func TestTemplatePrinterPrintMethods(t *testing.T) { // TODO: Replace "Template"
 		})
 	})
 }
-```
\ No newline at end of file
+```
diff --git a/_examples/bigtext/main.go b/_examples/bigtext/main.go
new file mode 100644
index 00000000..11d8bb85
--- /dev/null
+++ b/_examples/bigtext/main.go
@@ -0,0 +1,12 @@
+package main
+
+import "github.com/pterm/pterm"
+
+func main() {
+	pterm.DefaultBigText.WithLetters(pterm.NewLettersFromText("PTerm")).Render()
+
+	pterm.DefaultBigText.WithLetters(
+		pterm.NewLettersFromTextWithStyle("P", pterm.NewStyle(pterm.FgCyan)),
+		pterm.NewLettersFromTextWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
+		Render()
+}
diff --git a/_examples/demo/main.go b/_examples/demo/main.go
index 695c8644..378f77d2 100644
--- a/_examples/demo/main.go
+++ b/_examples/demo/main.go
@@ -64,8 +64,11 @@ func pseudoApplicationHeader() *pterm.TextPrinter {
 }
 
 func introScreen() {
-	pterm.DefaultHeader.WithBackgroundStyle(pterm.NewStyle(pterm.BgLightBlue)).WithMargin(10).Println(
-		"PTDP - PTerm Demo Program")
+	pterm.DefaultBigText.WithLetters(
+		pterm.NewLettersFromTextWithStyle("P", pterm.NewStyle(pterm.FgCyan)),
+		pterm.NewLettersFromTextWithStyle("Term", pterm.NewStyle(pterm.FgLightMagenta))).
+		Render()
+
 	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!" +
diff --git a/bigtext_printer.go b/bigtext_printer.go
new file mode 100644
index 00000000..cdb37baf
--- /dev/null
+++ b/bigtext_printer.go
@@ -0,0 +1,530 @@
+package pterm
+
+import (
+	"github.com/mattn/go-runewidth"
+	"github.com/pterm/pterm/internal"
+	"strings"
+)
+
+// Letters is a slice of Letter.
+type Letters []Letter
+
+// NewLettersFromText creates a Letters object from a string, which is prefilled with the LetterStyle from ThemeDefault.
+// You can override the ThemeDefault LetterStyle if you want to.
+func NewLettersFromText(text string) Letters {
+	return NewLettersFromTextWithStyle(text, &ThemeDefault.LetterStyle)
+}
+
+// NewLettersFromTextWithStyle creates a Letters object from a string and applies a Style to it.
+func NewLettersFromTextWithStyle(text string, style *Style) Letters {
+	s := strings.Split(text, "")
+	l := Letters{}
+
+	for _, s2 := range s {
+		l = append(l, Letter{
+			String: s2,
+			Style:  style,
+		})
+	}
+
+	return l
+}
+
+// Letter is an object, which holds a string and a specific Style for it.
+type Letter struct {
+	String string
+	Style  *Style
+}
+
+// WithStyle returns a new Letter with a specific Style.
+func (l Letter) WithStyle(style *Style) *Letter {
+	l.Style = style
+	return &l
+}
+
+// WithString returns a new Letter with a specific String.
+func (l Letter) WithString(s string) *Letter {
+	l.String = s
+	return &l
+}
+
+// BigTextPrinter renders big text.
+// You can use this as title screen for your application.
+type BigTextPrinter struct {
+	// BigCharacters holds the map from a normal character to it's big version.
+	BigCharacters map[string]string
+	Letters       Letters
+}
+
+// WithBigCharacters returns a new BigTextPrinter with specific BigCharacters.
+func (p BigTextPrinter) WithBigCharacters(chars map[string]string) *BigTextPrinter {
+	p.BigCharacters = chars
+	return &p
+}
+
+// WithLetters returns a new BigTextPrinter with specific Letters
+func (p BigTextPrinter) WithLetters(letters ...Letters) *BigTextPrinter {
+	l := Letters{}
+	for _, letter := range letters {
+		l = append(l, letter...)
+	}
+	p.Letters = l
+	return &p
+}
+
+// Srender renders the Template as a string.
+func (p BigTextPrinter) Srender() string {
+	var ret string
+	var bigLetters Letters
+	for _, l := range p.Letters {
+		if val, ok := p.BigCharacters[l.String]; ok {
+			bigLetters = append(bigLetters, Letter{
+				String: val,
+				Style:  l.Style,
+			})
+		}
+	}
+
+	var maxHeight int
+
+	for _, l := range bigLetters {
+		h := strings.Count(l.String, "\n")
+		if h > maxHeight {
+			maxHeight = h
+		}
+	}
+
+	for i := 0; i <= maxHeight; i++ {
+		for _, letter := range bigLetters {
+			var letterLine string
+			letterLines := strings.Split(letter.String, "\n")
+			maxLetterWidth := internal.GetMaxStringMaxWidth(letter.String)
+			if len(letterLines) > i {
+				letterLine = letterLines[i]
+			}
+			letterLineLength := runewidth.StringWidth(letterLine)
+			if letterLineLength < maxLetterWidth {
+				letterLine += strings.Repeat(" ", maxLetterWidth-letterLineLength)
+			}
+			ret += letter.Style.Sprint(letterLine)
+		}
+		ret += "\n"
+	}
+
+	return ret
+}
+
+// Render prints the Template to the terminal.
+func (p BigTextPrinter) Render() {
+	Println(p.Srender())
+}
+
+// DefaultBigText contains default values for BigTextPrinter.
+var DefaultBigText = BigTextPrinter{
+	BigCharacters: map[string]string{
+		"a": ` █████  
+██   ██ 
+███████ 
+██   ██ 
+██   ██ `,
+		"A": ` █████  
+██   ██ 
+███████ 
+██   ██ 
+██   ██ `,
+		"b": `██████  
+██   ██ 
+██████  
+██   ██ 
+██████`,
+		"B": `██████  
+██   ██ 
+██████  
+██   ██ 
+██████`,
+		"c": ` ██████ 
+██      
+██      
+██      
+ ██████`,
+		"C": ` ██████ 
+██      
+██      
+██      
+ ██████`,
+		"d": `██████  
+██   ██ 
+██   ██ 
+██   ██ 
+██████ `,
+		"D": `██████  
+██   ██ 
+██   ██ 
+██   ██ 
+██████ `,
+		"e": `███████ 
+██      
+█████   
+██      
+███████`,
+		"E": `███████ 
+██      
+█████   
+██      
+███████`,
+		"f": `███████ 
+██      
+█████   
+██      
+██     `,
+		"F": `███████ 
+██      
+█████   
+██      
+██     `,
+		"g": ` ██████  
+██       
+██   ███ 
+██    ██ 
+ ██████  `,
+		"G": ` ██████  
+██       
+██   ███ 
+██    ██ 
+ ██████  `,
+		"h": `██   ██ 
+██   ██ 
+███████ 
+██   ██ 
+██   ██ `,
+		"H": `██   ██ 
+██   ██ 
+███████ 
+██   ██ 
+██   ██ `,
+		"i": `██ 
+██ 
+██ 
+██ 
+██`,
+		"I": `██ 
+██ 
+██ 
+██ 
+██`,
+		"j": `     ██ 
+     ██ 
+     ██ 
+██   ██ 
+ █████ `,
+		"J": `     ██ 
+     ██ 
+     ██ 
+██   ██ 
+ █████ `,
+		"k": `██   ██ 
+██  ██  
+█████   
+██  ██  
+██   ██`,
+		"K": `██   ██ 
+██  ██  
+█████   
+██  ██  
+██   ██`,
+		"l": `██      
+██      
+██      
+██      
+███████ `,
+		"L": `██      
+██      
+██      
+██      
+███████ `,
+		"m": `███    ███ 
+████  ████ 
+██ ████ ██ 
+██  ██  ██ 
+██      ██`,
+		"M": `███    ███ 
+████  ████ 
+██ ████ ██ 
+██  ██  ██ 
+██      ██`,
+		"n": `███    ██ 
+████   ██ 
+██ ██  ██ 
+██  ██ ██ 
+██   ████`,
+		"N": `███    ██ 
+████   ██ 
+██ ██  ██ 
+██  ██ ██ 
+██   ████`,
+		"o": ` ██████  
+██    ██ 
+██    ██ 
+██    ██ 
+ ██████  `,
+		"O": ` ██████  
+██    ██ 
+██    ██ 
+██    ██ 
+ ██████  `,
+		"p": `██████  
+██   ██ 
+██████  
+██      
+██     `,
+		"P": `██████  
+██   ██ 
+██████  
+██      
+██     `,
+		"q": ` ██████  
+██    ██ 
+██    ██ 
+██ ▄▄ ██ 
+ ██████  
+    ▀▀   `,
+		"Q": ` ██████  
+██    ██ 
+██    ██ 
+██ ▄▄ ██ 
+ ██████  
+    ▀▀   `,
+		"r": `██████  
+██   ██ 
+██████  
+██   ██ 
+██   ██`,
+		"R": `██████  
+██   ██ 
+██████  
+██   ██ 
+██   ██`,
+		"s": `███████ 
+██      
+███████ 
+     ██ 
+███████`,
+		"S": `███████ 
+██      
+███████ 
+     ██ 
+███████`,
+		"t": `████████ 
+   ██    
+   ██    
+   ██    
+   ██    `,
+		"T": `████████ 
+   ██    
+   ██    
+   ██    
+   ██    `,
+		"u": `██    ██ 
+██    ██ 
+██    ██ 
+██    ██ 
+ ██████ `,
+		"U": `██    ██ 
+██    ██ 
+██    ██ 
+██    ██ 
+ ██████ `,
+		"v": `██    ██ 
+██    ██ 
+██    ██ 
+ ██  ██  
+  ████   `,
+		"V": `██    ██ 
+██    ██ 
+██    ██ 
+ ██  ██  
+  ████   `,
+		"w": `██     ██ 
+██     ██ 
+██  █  ██ 
+██ ███ ██ 
+ ███ ███ `,
+		"W": `██     ██ 
+██     ██ 
+██  █  ██ 
+██ ███ ██ 
+ ███ ███ `,
+		"x": `██   ██ 
+ ██ ██  
+  ███   
+ ██ ██  
+██   ██ `,
+		"X": `██   ██ 
+ ██ ██  
+  ███   
+ ██ ██  
+██   ██ `,
+		"y": `██    ██ 
+ ██  ██  
+  ████   
+   ██    
+   ██   `,
+		"Y": `██    ██ 
+ ██  ██  
+  ████   
+   ██    
+   ██   `,
+		"z": `███████ 
+   ███  
+  ███   
+ ███    
+███████`,
+		"Z": `███████ 
+   ███  
+  ███   
+ ███    
+███████`,
+		"0": ` ██████  
+██  ████ 
+██ ██ ██ 
+████  ██ 
+ ██████ `,
+		"1": ` ██ 
+███ 
+ ██ 
+ ██ 
+ ██ `,
+		"2": `██████  
+     ██ 
+ █████  
+██      
+███████ `,
+		"3": `██████  
+     ██ 
+ █████  
+     ██ 
+██████ `,
+		"4": `██   ██ 
+██   ██ 
+███████ 
+     ██ 
+     ██ `,
+		"5": `███████ 
+██      
+███████ 
+     ██ 
+███████ 
+       `,
+		"6": ` ██████  
+██       
+███████  
+██    ██ 
+ ██████ `,
+		"7": `███████ 
+     ██ 
+    ██  
+   ██   
+   ██`,
+		"8": ` █████  
+██   ██ 
+ █████  
+██   ██ 
+ █████ `,
+		"9": ` █████  
+██   ██ 
+ ██████ 
+     ██ 
+ █████  
+        `,
+		" ": "    ",
+		"!": `██ 
+██ 
+██ 
+   
+██ `,
+		"$": `▄▄███▄▄·
+██      
+███████ 
+     ██ 
+███████ 
+  ▀▀▀  `,
+		"%": `██  ██ 
+   ██  
+  ██   
+ ██    
+██  ██`,
+		"/": `    ██ 
+   ██  
+  ██   
+ ██    
+██     
+       `,
+		"(": ` ██ 
+██  
+██  
+██  
+ ██ `,
+		")": `██  
+ ██ 
+ ██ 
+ ██ 
+██  `,
+		"?": `██████  
+     ██ 
+  ▄███  
+  ▀▀    
+  ██   `,
+		"[": `███ 
+██  
+██  
+██  
+███`,
+		"]": `███ 
+ ██ 
+ ██ 
+ ██ 
+███ `,
+		".": `   
+   
+   
+   
+██`,
+		",": `   
+   
+   
+   
+▄█`,
+		"-": `      
+      
+█████ 
+      
+      
+      
+     `,
+		"<": `  ██ 
+ ██  
+██   
+ ██  
+  ██ `,
+		">": `██   
+ ██  
+  ██ 
+ ██  
+██ `,
+		"*": `      
+▄ ██ ▄
+ ████ 
+▀ ██ ▀
+     `,
+		"#": ` ██  ██  
+████████ 
+ ██  ██  
+████████ 
+ ██  ██ `,
+		"_": `        
+        
+        
+        
+███████ `,
+	},
+}
diff --git a/go.mod b/go.mod
index 723b41cc..ac969644 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,9 @@ go 1.15
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/gookit/color v1.3.1
+	github.com/mattn/go-runewidth v0.0.9
 	github.com/stretchr/testify v1.6.1
-	golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0
-	golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect
+	golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
+	golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a // indirect
+	gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
 )
diff --git a/go.sum b/go.sum
index 2a47551b..23712ae8 100644
--- a/go.sum
+++ b/go.sum
@@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/gookit/color v1.3.1 h1:PPD/C7sf8u2L8XQPdPgsWRoAiLQGZEZOzU3cf5IYYUk=
 github.com/gookit/color v1.3.1/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
@@ -15,14 +17,21 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
+golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/letters v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
 golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a h1:e3IU37lwO4aq3uoRKINC7JikojFmE5gO7xhfxs8VC34=
+golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/max_text_width.go b/internal/max_text_width.go
new file mode 100644
index 00000000..a6391ad7
--- /dev/null
+++ b/internal/max_text_width.go
@@ -0,0 +1,18 @@
+package internal
+
+import (
+	"github.com/mattn/go-runewidth"
+	"strings"
+)
+
+// GetMaxStringMaxWidth returns the maximum width of a string with multiple lines.
+func GetMaxStringMaxWidth(s string) int {
+	var max int
+	ss := strings.Split(s, "\n")
+	for _, s2 := range ss {
+		if runewidth.StringWidth(s2) > max {
+			max = runewidth.StringWidth(s2)
+		}
+	}
+	return max
+}
diff --git a/theme.go b/theme.go
index 823d16e3..765e6200 100644
--- a/theme.go
+++ b/theme.go
@@ -32,6 +32,7 @@ var (
 		SectionStyle:            Style{Bold, FgYellow},
 		ListTextStyle:           Style{FgWhite},
 		ListBulletStyle:         Style{FgGray},
+		LetterStyle:             Style{FgDefault},
 	}
 )
 
@@ -67,6 +68,7 @@ type Theme struct {
 	SectionStyle            Style
 	ListTextStyle           Style
 	ListBulletStyle         Style
+	LetterStyle             Style
 }
 
 // WithPrimaryStyle returns a new theme with overridden value.
@@ -170,3 +172,9 @@ func (t Theme) WithListBulletStyle(style Style) Theme {
 	t.ListBulletStyle = style
 	return t
 }
+
+// WithLetterStyle returns a new theme with overridden value.
+func (t Theme) WithLetterStyle(style Style) Theme {
+	t.LetterStyle = style
+	return t
+}


Test patch:
diff --git a/bigtext_printer_test.go b/bigtext_printer_test.go
new file mode 100644
index 00000000..d56b2b98
--- /dev/null
+++ b/bigtext_printer_test.go
@@ -0,0 +1,96 @@
+package pterm
+
+import (
+	"github.com/pterm/pterm/internal"
+	"github.com/stretchr/testify/assert"
+	"io"
+	"testing"
+)
+
+func TestBigTextPrinterNilPrint(t *testing.T) {
+	p := BigTextPrinter{}
+	p.Render()
+}
+
+func TestBigTextPrinter_Render(t *testing.T) {
+	internal.TestDoesOutput(t, func(w io.Writer) {
+		DefaultBigText.WithLetters(NewLettersFromText("Hello")).Render()
+	})
+}
+
+func TestBigTextPrinter_WithBigCharacters(t *testing.T) {
+	e := map[string]string{"a": "b", "c": "d"}
+	p := BigTextPrinter{}
+	p2 := p.WithBigCharacters(e)
+
+	assert.Equal(t, e, p2.BigCharacters)
+	assert.Empty(t, p.BigCharacters)
+}
+
+func TestBigTextPrinter_WithLetters(t *testing.T) {
+	e := Letters{
+		Letter{
+			String: "test",
+			Style:  NewStyle(FgRed, BgBlue, Bold),
+		},
+		Letter{
+			String: "test2",
+			Style:  NewStyle(FgRed, BgBlue, Bold),
+		},
+	}
+	p := BigTextPrinter{}
+	p2 := p.WithLetters(e)
+
+	assert.Equal(t, e, p2.Letters)
+	assert.Empty(t, p.Letters)
+}
+
+func TestLetter_WithString(t *testing.T) {
+	e := "Hello, World!"
+	p := Letter{}
+	p2 := p.WithString(e)
+
+	assert.Equal(t, e, p2.String)
+	assert.Empty(t, p.String)
+}
+
+func TestLetter_WithStyle(t *testing.T) {
+	p := Letter{}
+	s := NewStyle(FgRed, BgRed, Bold)
+	p2 := p.WithStyle(s)
+
+	assert.Equal(t, s, p2.Style)
+	assert.Empty(t, p.Style)
+}
+
+func TestNewLettersFromText(t *testing.T) {
+	e := Letters{
+		Letter{
+			String: "a",
+			Style:  &ThemeDefault.LetterStyle,
+		},
+		Letter{
+			String: "b",
+			Style:  &ThemeDefault.LetterStyle,
+		},
+	}
+	p := NewLettersFromText("ab")
+
+	assert.Equal(t, e, p)
+}
+
+func TestNewLettersFromTextWithStyle(t *testing.T) {
+	e := Letters{
+		Letter{
+			String: "a",
+			Style:  NewStyle(FgRed, BgBlue, Bold),
+		},
+		Letter{
+			String: "b",
+			Style:  NewStyle(FgRed, BgBlue, Bold),
+		},
+	}
+	p := NewLettersFromTextWithStyle("ab", NewStyle(FgRed, BgBlue, Bold))
+
+	assert.Equal(t, e, p)
+}
diff --git a/internal/test_utils.go b/internal/test_utils.go
index 2fe883a3..01ce572a 100644
--- a/internal/test_utils.go
+++ b/internal/test_utils.go
@@ -72,6 +72,11 @@ func TestSprintlnContains(t *testing.T, logic func(a interface{}) string) {
 	}
 }
 
+// TestDoesOutput can be used to test if something is outputted to stdout.
+func TestDoesOutput(t *testing.T, logic func(w io.Writer)) {
+	assert.NotEmpty(t, CaptureStdout(logic))
+}
+
 // CaptureStdout captures everything written to the terminal and returns it as a string.
 func CaptureStdout(f func(w io.Writer)) string {
 	originalStdout := os.Stdout
diff --git a/theme_test.go b/theme_test.go
index 3bdf6a65..8e14e942 100644
--- a/theme_test.go
+++ b/theme_test.go
@@ -140,3 +140,11 @@ func TestTheme_WithListTextStyle(t *testing.T) {
 
 	assert.Equal(t, s, p2.ListTextStyle)
 }
+
+func TestTheme_WithLetterStyle(t *testing.T) {
+	s := Style{FgRed, BgBlue, Bold}
+	p := Theme{}
+	p2 := p.WithLetterStyle(s)
+
+	assert.Equal(t, s, p2.LetterStyle)
+}