README ¶
Go Color Term
Welcome to Go Color Term! the place where your monochromatic terminal meets a colorful world!
This library allows to apply ANSI Escape Sequences to alter the style of the rendered text on a Terminal.
Project Status
The project follows Semantic Versioning, so the rule for 0.x releases applies. This means that the public API shouldn't be considered stable.
That said, all the current forms of using the library (described in the sections below) are in a working state.
Supported Operating Systems and Terminals
Linux, macOS and Windows are supported. See the sections belows for specific details of each platform.
Linux
It should work out of the box with most terminal/shell combinations.
macOS
Support in macOS should be pretty decent, but perhaps some settings must be manually enabled in the terminal for some features.
Terminal | Shell | Notes |
Terminal 2.11 (440) |
Zsh 5.8 |
✅ Working |
Bash 3.2.57 |
✅ Working | |
iTerm2[1][2][3] 3.4.4 |
Zsh 5.8 |
✅ Working[4] |
Bash 3.2.57 |
✅ Working[4] |
[1] Bold support requires "Draw bold text in bold font" to be enabled in terminal profile.
[2] Italics support requires "Italic text" to be enabled in terminal profile.
[3] Blink support requires "Blinking text" to be enabled in terminal profile.
[4] Conceal not supported.
Windows
Support in Windows is pretty decent too, but limitations are present in some terminals or with some terminal/shell combinations.
Terminal | Shell | Notes |
conhost.exe[1][6] 10.0.19041.746 |
CMD 10.0.19041.746 |
✅ Working[2][3][4][5] |
Windows PowerShell 5.1 (19041.868) |
✅ Working[2][3][4][5] | |
PowerShell Core 7.1.3 |
✅ Working[2][3][4][5] | |
Windows Terminal 1.6.10571.0 |
CMD 10.0.19041.746 |
✅ Working |
Windows PowerShell 5.1 (19041.868) |
✅ Working | |
PowerShell Core 7.1.3 |
✅ Working | |
Bash 4.4.23 |
❌ Not working | |
mintty 3.4.6 |
Bash 4.4.23 |
✅ Working[3] |
VS Code integrated terminal 1.54.3 |
CMD 10.0.19041.746 |
✅ Working[2][3][5] |
[1] You might need to enable support for it.
[2] Faint not supported.
[3] Blink not supported.
[4] Conceal not supported.
[5] Strikethrough not supported.
[6] Bold seems to increase font brightness not font weight.
Examples
Check the accompanying repository with a ready-to-run app which recopiles various examples to showcase the library API.
How to use
This library provides several ways to add color to your output, tailored for different use cases.
The idea is to provide with the simplest way to render styled text for each situation.
Method | Use Case |
---|---|
coloring.* utility functions |
Simple, ad-hoc styling |
StyleBuilder |
Combining multiple styles; reusing the same style for various strings |
StyledText |
Sealed, self-contained styled string useful for passing around |
SentenceBuilder |
Complex styling; full control of placing (start and end) of style attributes |
coloring.Tagged |
Custom markup syntax to embed color attributes directly in a string |
The next sections describes each of these approaches in more detail.
In the examples below, whenever you encounter the string sequence ESC
, it symbolically refers the the byte 0x1B
(27
in decimal or 33
in octal) which is the control character used to start the ANSI escape sequences.
coloring.*
utility functions
These are utility functions that lets you apply simple style attributes to a provided string, like:
coloring.Red("Fire truck")
This will produce the following escaped string:
ESC[31mFire truckESC[39m
Which be can decompose for analysis into:
Sets red Resets text color
text color to default
| |
v v
------- -------
ESC[31mFire truckESC[39m
----------
^
|
Provided string
Of course you can combine multiple styles by passing the output of one function to another:
coloring.Bold(coloring.Red("Wolf"))
This is probably fine for a few function calls, but can become difficult to read if the combination grows larger.
Also, this approach, while it works, doesn't generate the most efficient escape sequences:
ESC[1mESC[31mWolfESC[39mESC[22m
A more compact sequence for the same style would be ESC[1;31mWolfESC[0m
, which is the topic of the next section.
The full list of utility functions is:
Black(s string)
Red(s string)
Green(s string)
Yellow(s string)
Blue(s string)
Magenta(s string)
Cyan(s string)
White(s string)
BgBlack(s string)
BgRed(s string)
BgGreen(s string)
BgYellow(s string)
BgBlue(s string)
BgMagenta(s string)
BgCyan(s string)
BgWhite(s string)
Bold(s string)
Faint(s string)
Italic(s string)
Underline(s string)
Blink(s string)
Invert(s string)
Conceal(s string)
Strikethrough(s string)
Also, and to not pollute the coloring
package API surface with too many functions, an Extras
field exposes additional non-standard or not widely supported features.
Most notably, this includes bright versions for text and background colors, like coloring.Extras.BrightRed
.
The full list of extra functions is:
BrightBlack(s string)
BrightRed(s string)
BrightGreen(s string)
BrightYellow(s string)
BrightBlue(s string)
BrightMagenta(s string)
BrightCyan(s string)
BrightWhite(s string)
BgBrightBlack(s string)
BgBrightRed(s string)
BgBrightGreen(s string)
BgBrightYellow(s string)
BgBrightBlue(s string)
BgBrightMagenta(s string)
BgBrightCyan(s string)
BgBrightWhite(s string)
See coloring/utility.go for implementation details.
StyleBuilder
When you need to apply multiple styles to the same word/phrase you can use a StyleBuilder
:
boldRedFiretruck := coloring.For("fire truck").Bold().Red()
Then you can use it as a string
argument for formatting functions:
fmt.Printf("Here comes the %s\n", boldRedFiretruck)
That's because StyleBuilder
implements the Stringer
interface.
If you need the styled string
for use in other contexts not expecting a Stringer
, just call the String()
func on the StyleBuilder
:
styledFiretruck := boldRedFiretruck.String()
// pass or use the styledFiretruck string as needed
Styles generated by StyleBuilder
combine multiple attributes in a single escape sequence and resets all the styles at the end. For example, the following code:
styledWolf := coloring.For("Wolf").Red().Bold().Underline().Blink().String()
creates the escaped string:
ESC[31;1;4;5mWolfESC[0m
If you pretend to reuse the same style for different string
s, you can do so by using the New()
shorthand, and then calling Func()
at the end, which will give you a ColorizerFunc
that can be invoked with different string
s:
boldRed := coloring.New().Bold().Red().Func()
fmt.Printf("Here comes the %s to extinguish the %s\n", boldRed("fire truck"), boldRed("fire"))
Whether to use For(string)
or New()
+ Func()
will be a matter of reusability needs.
Finally, if you only need to print the styled text and nothing else, StyleBuilder
offers a convenience function: Print()
.
It returns a ColorizerPrint
which can be invoked with the text to print, much like the ColorizerFunc
, but instead of returning the styled string
, it only outputs on the terminal:
printAlert := coloring.New().White().Bold().Background().Red().Print()
printAlert("ALERT: The house is on fire!!!\n")
And now you also know why the firemen were coming in the first place!
StyleBuilder
provides functions for the following:
- Set basic colors:
Black()
,Red()
,Green()
,Yellow()
,Blue()
,Magenta()
,Cyan()
,White()
. - Set custom colors:
- 8-bit colors:
Color(int)
passing a number in the range 0-255 (use constants oncoloring
package for the first 0-15 values). - 24-bit colors:
ColorRgb(int, int, int)
passing numbers in the 0-255 range for each RGB component.
- 8-bit colors:
- Set background color:
Background()
+ equivalent methods. - Set other style attributes:
Bold()
,Faint()
,Italic()
,Underline()
,Blink()
,Invert()
,Strikethrough()
.
StyledText
This can be considered a spin-off from StyleBuilder
that lets you get a "sealed" styled string which can't be further modified.
The StyledText
struct also implements Stringer
, so it can be used as a parameter for any function expecting one.
The motivation behind this type is to allow for the separation between styled text definition and usage. You can create a StyleBuilder
at program start, and then get multiple StyledText
s that you can pass around to the rest of the program handling console output.
The main (and only) difference to a plain string
is that StyledText
also contains an Unformatted()
function which returns the original, unstyled string
. This could come in handy if for some reason you need to alternate the display of the styled text and the plain text (i.e.: the one without styles).
The following example tries to illustrate the idea.
func main() {
boldGreenTextBuilder := coloring.New().Bold().Green()
successfulTitle := boldGreenTextBuilder.StyleText("successful")
successTitle := boldGreenTextBuilder.StyleText("succeeded")
pipeline(successfulTitle, successTitle)
}
func pipeline(successTitle, successfulTitle *coloring.StyledText) {
fmt.Println("BUILDING...")
// "building"
fmt.Println("...")
fmt.Println("...")
fmt.Println("...")
fmt.Println()
fmt.Printf("Build %s.\n", successfulTitle)
fmt.Println()
fmt.Println("RUNNING TESTS...")
// "testing"
fmt.Println("...")
fmt.Println("...")
fmt.Println()
fmt.Printf("Running tests: all tests %s.", successTitle)
fmt.Println()
}
SentenceBuilder
This is perhaps the most cumbersome way to add style attributes, but in return it provides more granular control to mark the start and end of each style attribute.
The biggest advantage is that you can apply styles that spans different sections of the text in a non-uniform way, like crossed text covering bold red text and regular text.
Of course this is also doable with the other APIs, but it will be more repetitive to accomplish.
coloring.Sentence().
StrikethroughStart().
ColorSet(coloring.RED).
Bold("All this text").
ColorReset().
Text(" is crossed").
Println()
Multiple things are going on there:
StrikethroughStart()
marks the start of crossed text.ColorSet(coloring.RED)
marks the start of red text.Bold("All this text")
outputs the given text with bold style.ColorReset()
sets text color back to the default one.Text(" is crossed")
adds normal (non-styled) text.Println()
resets all styles and then prints the whole sentence tostdout
.
All the functions of the SentenceBuilder
API comes in two flavours:
- One that outputs a single chunk of text with a single style (like
Bold("All this text")
in the example above). - A pair of functions in the form
XXXStart
/XXXEnd
that lets you start some style and leave it "open" until you call the corresponding "end" function, much like closing an HTML tag.ColorSet
/ColorReset
are the exception to this naming convention, but serves the same purpose.
You might notice that we didn't call StrikethroughEnd
on the previous example. But that's fine, since we are ending the sentence with Println()
, which adds the attribute to reset al styles before writing the output. The rationale behind this is to not "leak" any styles in subsequent output.
Dissecting the generated string will complete the picture:
Strikethrough starts Bold starts Bold ends All attributes cleared
| | | |
v v v v
------ ------ ------- ------
ESC[9mESC[38;5;1mESC[1mAll this textESC[22mESC[39m is crossedESC[0m
----------- -------
^ ^
| |
Red color set Color reset
Given that the SentenceBuilder
API is quite large, there are no color-named functions for setting colored text/background, as it will expand the API surface further. There's only one method to write colored text/background which expects to receive the color number as a parameter (and equivalent ones for RGB colors).
As with StyleBuilder
, SentenceBuilder
also lets you grab a StyledText
containing the buffered styled text so far, as well the unformatted text.
The full list of SentenceBuilder
functions is:
Text
Color
,ColorSet
,ColorRgb
,ColorRgbSet
,ColorReset
Background
,BackgroundSet
,BackgroundRgb
,BackgroundRgbSet
,BackgroundReset
Bold
,BoldStart
,BoldEnd
Faint
,FaintStart
,FaintEnd
Italic
,ItalicStart
,ItalicEnd
Underline
,UnderlineStart
,UnderlineEnd
Blink
,BlinkStart
,BlinkEnd
Invert
,InvertStart
,InvertEnd
Conceal
,ConcealStart
,ConcealEnd
Strikethrough
,StrikethroughStart
,StrikethroughEnd
Reset
String
,Print
,PrintAndClear
,Println
,PrintlnAndClear
,StyledText
See coloring/sentence_builder.go for full documentation on each function.
coloring.Tagged
The SentenceBuilder
API, while powerful, is very verbose and can produce hard-to-read code.
The coloring.Tagged
function aims to provide pretty much the same fine grained control, while keeping your strings more readable and less fragmented across different function calls.
It allows you to use an HTML-like syntax in your strings to set the starting and ending points of style attributes.
HTML-like tags were chosen because probably most developers have worked with HTML, so the resulting strings will result familiar to them.
For example, to create a styled string you can write:
coloring.Tagged("The <b>wolf</b> <i>howls</i> at the <b><yellow>moon</yellow></b>")
This will result in the word wolf
styled as bold text, the word howls
in italics, and the word moon
in bold and yellow color. It will show up in the console like:
The examples on this section omits the
fmt.Println()
(or equivalent) that is neccessary to output the returned string on the console.
The full list of tags that can be used are:
Attribute | Tag | Shorthand |
---|---|---|
Bold | <bold> | <b> |
Faint | <faint> | <f> |
Italic | <italic> | <i> |
Underline | <underline> | <u> |
Blink | <blink> | <bl> |
Invert | <invert> | <in> |
Conceal | <conceal> | <c> |
Strikethrough | <strikethrough> | <s> |
Black text | <black> | N/A |
Red text | <red> | N/A |
Green text | <green> | N/A |
Yellow text | <yellow> | N/A |
Blue text | <blue> | N/A |
Magenta text | <magenta> | N/A |
Cyan text | <cyan> | N/A |
White text | <white> | N/A |
Black background | <bg-black> | N/A |
Red background | <bg-red> | N/A |
Green background | <bg-green> | N/A |
Yellow background | <bg-yellow> | N/A |
Blue background | <bg-blue> | N/A |
Magenta background | <bg-magenta> | N/A |
Cyan background | <bg-cyan> | N/A |
White background | <bg-white> | N/A |
Reset all attributes | <reset> | <r> |
Note that, unlike real HTML, these tags are only used to mark the starting and ending points of the style attribute they represent, but they don't requiere to be correctly nested.
The following code will produce a valid escaped string:
coloring.Tagged("<b>Lorem ipsum <red>dolor sit </b>amet</red>")
Because it's translated to:
<b> <red> </b> </red>
| | | |
v v v v
------ ----------- ------- -------
ESC[1mLorem ipsum ESC[38;5;1mdolor sit ESC[22mametESC[39mESC[0m
------
^
|
Reset attribute automatically
added at the end of the string
Also, because a reset attribute (ESC[0m
) is automatically added at the end of the generated string (so it doesn't leak styles to the next console output), it would be possible to leave open tags that set styles that doesn't change anymore in the current string:
coloring.Tagged("<b>Starting bold and <green>turning green")
As you may guess, this produces the escaped string:
ESC[1mStarting bold and ESC[38;5;2mturning greenESC[0m
which is a valid escaped sequence that is rendered like:
If you feel more comfortable with the "simmetry" of regular HTML, you can also write:
coloring.Tagged("<b>Starting bold and <green>turning green</green></b>")
Which produces the same visual output, although with a bit more redundant escape sequence:
ESC[1mStarting bold and ESC[38;5;2mturning greenESC[39mESC[22mESC[0m
One could say that the latter form is more maintainable because in case you need to move things around, it's more easy to spot the boundaries of each attribute. Performance impact should be negligible.
But in the end, it's up to you to decide which style might be the "best" for your specific scenario, taste, etc.
Bright colors
You can also set bright color mode for any text or background color adding the attribute bright
inside the tag (similar to how the disabled
attribute can be specified in the HTML <select>
element):
coloring.Tagged("<red bright>Bright color</red> and <bg-green bright>bright background</bg-green> enabled!")
Remember:
bright
should be interpreted as an "attribute without value", and thus go after the tag name.
Resetting al style attributes at once
A special tag named <reset>
(shorthand <r>
) allows to insert the "reset" attribute (ESC[0m
) that turns off all other attributes at once.
This can come in handy if you have multiple style attributes applied and don't want to bother with closing each one individually:
coloring.Tagged("<bg-cyan bright><red bright><b><u><i>This starts very convoluted,<reset> but ends quietly.")
Tag escape
If your string actually contains the <
character as part of the text, you will need to escape it by prepending a \
character before it. The \
must itself be escaped in a string, so the final string will become:
coloring.Tagged("The \\<bold> or \\<b> tags are used to output <b>bold</b> text.")
In case that you need to output a \
character, you escape the \
by adding a \
before it.
Licence
This project is licensed under the terms of the MIT License.
Contributing
Feel free to add contributions in the form of issues, pull requests or discussions.