Delightful console output for Swift developers.

Last update: May 18, 2022

Rainbow

Rainbow adds text color, background color and style for console and command line output in Swift. It is born for cross-platform software logging in terminals, working in both Apple's platforms and Linux.

Basic Usage

Nifty way, using the String extension, and print the colorized string.

Named Color & Style

import Rainbow

print("Red text".red)
print("Blue background".onBlue)
print("Light green text on white background".lightGreen.onWhite)

print("Underline".underline)
print("Cyan with bold and blinking".cyan.bold.blink)

print("Plain text".red.onYellow.bold.clearColor.clearBackgroundColor.clearStyles)

It gives you something like this:

Installation

Swift Package Manager

If you are developing a cross platform software in Swift, Swift Package Manager might be your choice for package management. Just add the url of this repo to your Package.swift file as a dependency:

import PackageDescription

let package = Package(
    name: "YourAwesomeSoftware",
    dependencies: [
        .package(url: "https://github.com/onevcat/Rainbow", .upToNextMajor(from: "4.0.0"))
    ],
    targets: [
        .target(
            name: "MyApp",
            dependencies: ["Rainbow"]
        )
    ]
)

Then run swift build whenever you get prepared.

You could know more information on how to use Swift Package Manager in Apple's official page.

Other Usage

String Interpolation & Nested

Swift string interpolation is supported. Define the color for part of the string. Or even create nested colorful strings. The inner color style will be kept:

print("接天莲叶\("无穷碧".green),映日荷花\("别样红".red)")
print("\("两只黄鹂".yellow)鸣翠柳,一行白鹭\("上青天".lightBlue)".lightGreen.underline)

ANSI 256-Color Mode

8-bit color is fully supported, for both text color and background color:

print("停车坐爱\("枫林晚".bit8(31))\("霜叶".bit8(160))红于\("二月花".bit8(198))")
print("\("一道残阳".bit8(202))铺水中,\("半江瑟瑟".bit8(30).onBit8(226))半江红。")

Hex Colors (approximated)

It also accepts a Hex color. Rainbow tries to convert it to a most approximate .bit8 color:

print("黑云压城\("城欲摧".hex("#666")),甲光向日\("金鳞开".hex("000000").onHex("#E6B422"))")
print("日出江花\("红胜火".hex(0xd11a2d)),春来江水\("绿如蓝".hex(0x10aec2))")

Valid format: "FFF", "#FFF", "FFFFFF", "#FFFFFF", 0xFFFFFF

True color

A few terminal emulators supports 24-bit true color. If you are sure the 24-bit colors can be displayed in your user's terminal, Rainbow has no reason to refuse them!

print("疏影横斜\("水清浅".bit24(36,116,181)),暗香浮动\("月黄昏".bit24(254,215,26))")
print("\("春色满园".hex("#ea517f", to: .bit24))关不住,\("一枝红杏".hex("#f43e06", to: .bit24))出墙来。")

Output Target

By default, Rainbow should be smart enough to detect the output target, to determine if it is a tty. For example, it automatically output plain text if written to a file:

// main.swift
print("Hello Rainbow".red)

$ .build/debug/RainbowDemo > output.txt

// output.txt
Hello Rainbow

This is useful for sharing the same code for logging to console and to a log file.

You can manually change this behavior by either:

  • Set the Rainbow.outputTarget yourself.
  • Pass a "NO_COLOR" environment value when executing your app.
  • Or set the Rainbow.enabled to false.

Verbose Way

You can also use the more verbose way if you want:

import Rainbow
let output = "The quick brown fox jumps over the lazy dog"
                .applyingCodes(Color.red, BackgroundColor.yellow, Style.bold)
print(output) // Red text on yellow, bold of course :)

Or even construct everything from scratch:

let entry = Rainbow.Entry(
    segments: [
        .init(text: "Hello ", color: .named(.magenta)),
        .init(text: "Rainbow", color: .bit8(214), backgroundColor: .named(.lightBlue), styles: [.underline]),
    ]
)
print(Rainbow.generateString(for: entry))

Please remember, the string extensions (such as "Hello".red) is O(n). So if you are handling a huge string or very complex nesting, there might be a performance issue or hard to make things in stream. The manual way is a rescue for these cases.

Motivation and Compatibility

Thanks to the open source of Swift, developers now could write cross platform programs with the same language. And I believe the command line software would be the next great platform for Swift. Colorful and well-organized output always helps us to understand what happens. It is really a necessary utility to create wonderful software.

Rainbow should work well in both OS X and Linux terminals. It is smart enough to check whether the output is connected to a valid text terminal or not, to decide the log should be modified or not. This could be useful when you want to send your log to a file instead to console.

Contact

Follow and contact me on Twitter or Sina Weibo. If you find an issue, just open a ticket on it. Pull requests are warmly welcome as well.

Backers & Sponsors

Open-source projects cannot live long without your help. If you find Kingfisher is useful, please consider supporting this project by becoming a sponsor. Your user icon or company logo shows up on my blog with a link to your home page.

Become a sponsor through GitHub Sponsors. ❤️

License

Rainbow is released under the MIT license. See LICENSE for details.

GitHub

https://github.com/onevcat/Rainbow
Comments
  • 1. Add conversion from BackgroundColor to its Color counterpart

    Hey there. I'm trying to build a string similar to a Powerline prompt.

    It's a series of segments, separated by a custom powerline triangle glyph. The glyph is coloured predicably: the triangle part of is coloured based on the text colour, and the background is coloured based on the background. But the glyph exists to connect two different background colours.

    This means you want to set its text colour to the equivalent of the background colour of whats to the left, and the background colour to be equal to the background colour of whats to the right. To achieve this, you need a way of converting a BackgroundColor to its Color counterpart.

    Here's my example:

    import Rainbow
    
    extension BackgroundColor {
    	var toTextColor: Color {
    		switch self {
    		case .black:	return .black
    		case .red:		return .red
    		case .green:	return .green
    		case .yellow:	return .yellow
    		case .blue:		return .blue
    		case .magenta:	return .magenta
    		case .cyan:		return .cyan
    		case .white:	return .white
    		case .default:	return .default
    		}
    	}
    }
    
    struct Segment {
    	let text: String
    	let textColor: Color = .default
    	let backgroundColor: BackgroundColor
    }
    
    extension Collection where Element == Segment {
    	func joined() -> String {
    		let dummySegment = Segment(text: "", backgroundColor: .default)
    		
    		let strings = zip(self, self.dropFirst() + [dummySegment]).map { current, next -> String in
    			let separator = "".applyingCodes(current.backgroundColor.toTextColor, next.backgroundColor)
    			let text = current.text.applyingCodes(current.textColor, current.backgroundColor)
    			return text + separator
    		}
    		
    		return strings.joined()
    	}
    }
    
    let segments = [
    	Segment(text: "abc", backgroundColor: .red),
    	Segment(text: "def", backgroundColor: .green),
    	Segment(text: "ghi", backgroundColor: .blue),
    ]
    
    let result = segments.joined() + " The rest of the message"
    
    print("before\n")
    print(result)
    print("\nafter")
    

    Output (rendered in SF mono nerd font:

    image

    I wanted to contribute the implementation of toTextColor, because I think it might be useful to others. The reverse direction might also be useful, though there are more Colors than can map onto BackgroundColors, so its unclear how to handle the unmappable cases (make the computed property optional and return nil?)

    Do you think this would be useful for me to contribute?

    If so, how do you think I should write the test for it?

    Reviewed by amomchilov at 2021-02-09 02:59
  • 2. Updated for Swift 3.0 per 2016-05-09 development snapshot.

    Updated code to work with Swift 3.0-dev 2016-05-09 development snapshot. There should be a 3.0 public release candidate coming up in the next few weeks, might want to merge then (since this will probably break all 2.2 builds).

    Would also love some feedback, this is my first contribution to open source 🔥

    Reviewed by FredLoh at 2016-05-17 00:06
  • 3. Still black

    My logs are still black. When I set Environment Variable "XcodeColors" to YES, my output is like this: g255,0,0;Recognized a double tap[;

    Reviewed by dannogo at 2017-01-30 12:38
  • 4. No such module 'Rainbow'

    I followed the directions in the readme file and while I'm able to see Rainbow install when I add the .package(url: "https://github.com/onevcat/Rainbow", from: "3.0.0") line to the dependencies array, I get No such module Rainbow when I attempt to import it in main.swift.

    I tried adding it to targets, too, like so:

        targets: [
            .target(
                name: "MyCLIUtility",
                dependencies: ["SPMUtility", "Rainbow"]),
            .testTarget(
                name: "MyCLIUtilityTests",
                dependencies: ["MyCLIUtility"]),
        ]
    

    What am I missing?

    Reviewed by AdrianBinDC at 2020-02-25 03:49
  • 5. [NFC] Silence String.character access warning

    Use of String.character is now unnecessary as String is a sliceable collection all its own in Swift 4. This patch removes accesses to the characters collection and, in doing so, silences the warnings for its usage that appear in Xcode 9.1.

    Reviewed by CodaFi at 2017-11-03 23:39
  • 6. Cocopod 1.1 doesn't output colors

    Using Xcode 7.3 cocopods. I added Rainbow in the Podfile per your README. I also remembered to import RaindobowSwift (vs Rainbow). Now, when I try to use it, type-ahead shows me the colors so I know the class is being read. However, no text comes out colored. (ie print("hello myself".red) just prints "hello myself" in the normal console color. I feel like xcode is somehow overriding the coloring maybe.

    Ideas?

    PS I am in a bridged obj-c/swift project if that's a clue. However, I am only trying this from the Swift side without luck...

    Reviewed by world at 2016-06-15 15:56
  • 7. Different names in Package.swift and Podfile

    The inconsistency in naming (Rainbow / RainbowSwift) makes it difficult to build the same project using Xcode and SPM, without editing imports to one or the other.

    Reviewed by jnewc at 2017-02-27 01:21
  • 8. Assistance in writing a Regex to remove Rainbow information

    First of all, thank you for putting together this library. It's great work!

    I share your motivation that Swift will become incredibly useful for command line programs. This is the reason that I started SwiftyTextTable to better organize complex console output.

    I think our libraries are a natural pair, and I would like to make them work seamlessly together. Unfortunately, right now the escape sequences that Rainbow uses to inject color and style information are not compatible with my (rather naive) method of calculating string lengths to determine column widths. This is being tracked in this issue: scottrhoyt/SwiftyTextTable#5.

    It would be my preference to not introduce a dependency on Rainbow to keep the library as lightweight as possible. Therefore I was wondering if you could assist me in designing an algorithm to strip Rainbow styles and colors from a string for length calculations. From my light reading of the extraction methods already present in Rainbow, it looks like I can detect the presence of a formatted string, and if necessary, apply a regex to extract the text information out of the style information, but I would like to hear your thoughts on implementation. Thanks!

    Reviewed by scottrhoyt at 2016-03-03 19:10
  • 9. Style doesn't get reset for substring

    Hello,

    This simple code has an unexpected result:

    print(("a" + "b".underline + "c").lightGreen)
    

    I would expect the whole string to be in green, and the b only to be underlined, however the underlining doesn't get reset, so the c gets underlined too!

    Expected result: \e[92ma\e[92;4mb\e[0;92mc\e[0m Actual result: \e[92ma\e[92;4mb\e[92mc\e[0m abc with both b and c underlined

    This happens with all styles when applied to a substring where a foreground color is inherited.

    Reviewed by Snowy1803 at 2021-09-22 18:59
  • 10. Segment group doesn't work for `backgroundColor` and `styles`.

    Wei, thanks for your contribution to this project, my new tool relies on it strongly.

    After upgrading to the new version 4.0.0, I use the following code to join a colorful message in terminal console, but got something unexpected results:

    import RainbowSwift
    
    let entry = Rainbow.Entry(
        segments: [
            .init(text: "Hello ", color: .named(.magenta)),
            .init(text: "Rainbow ", color: .bit8(214), backgroundColor: .named(.black), styles: [.underline]),
            .init(text: "Hello ", color: .named(.magenta)/*, backgroundColor: .named(.default)*/),  // Comment 1
            .init(text: "again", color: .named(.magenta), backgroundColor: .named(.red)/*, styles: [.default]*/),  // Comment 2
        ]
    )
    print(Rainbow.generateString(for: entry))
    

    It shows the black background and styles from the second segment on the second Hello, this is weird, the underline style also affects to the last segment: 1

    If I uncomment the Comment 1 only: 2

    If I uncoment the Comment 2 only: 3

    Uncomment both: 4

    I really don't know how to explain them even after trying to look into the Rainbow inside, please confirm is it a bug or how should I use the Segment. Thanks!

    Reviewed by xingheng at 2021-08-22 14:06
  • 11. Empty output in a file

    In my command line tool, when I add > filename.txt to output results in a file, it creates an empty file. The output is provided in the console though.

    See more details: https://github.com/rsrbk/GoSwifty/issues/3

    Reviewed by rsrbk at 2020-11-01 20:26
A Swift-based API for reading from & writing to the Apple System Log (more commonly known somewhat inaccurately as "the console")
A Swift-based API for reading from & writing to the Apple System Log (more commonly known somewhat inaccurately as

CleanroomASL Notice: CleanroomASL is no longer supported The Apple System Log facility has been deprecated by Apple. As a result, we've deprecated Cle

Jan 29, 2022
XCLog is a Swift extension that helps you print something in console when debugging your projects.

XCLog XCLog is a Swift extension that helps you print something in console when debugging your projects. Installation Open Xcode > File > Add Packages

Jan 9, 2022
📱💬🚦 TinyConsole is a micro-console that can help you log and display information inside an iOS application, where having a connection to a development computer is not possible.
📱💬🚦 TinyConsole is a micro-console that can help you log and display information inside an iOS application, where having a connection to a development computer is not possible.

TinyConsole TinyConsole is a tiny log console to display information while using your iOS app and written in Swift. Usage Wrap your Main ViewControlle

Apr 26, 2022
Gedatsu provide readable format about AutoLayout error console log
Gedatsu provide readable format about AutoLayout error console log

Gedatsu Gedatsu provide readable format about AutoLayout error console log Abstract At runtime Gedatsu hooks console log and formats it to human reada

Apr 27, 2022
Customizable Console UI overlay with debug log on top of your iOS App
Customizable Console UI overlay with debug log on top of your iOS App

AEConsole Customizable Console UI overlay with debug log on top of your iOS App AEConsole is built on top of AELog, so you should probably see that fi

Mar 30, 2022
Gedatsu provide readable format about AutoLayout error console log
Gedatsu provide readable format about AutoLayout error console log

Gedatsu Gedatsu provide readable format about AutoLayout error console log Abstract At runtime Gedatsu hooks console log and formats it to human reada

Jun 24, 2021
Styling and coloring your XCTest logs on Xcode Console
Styling and coloring your XCTest logs on Xcode Console

XLTestLog Notes with Xcode 8 and XLTestLog Since Xcode 8 killed XcodeColors, the current way using XCTestLog on Xcode 8 is just plain texts with emoji

Feb 2, 2022
JustLog brings logging on iOS to the next level. It supports console, file and remote Logstash logging via TCP socket with no effort. Support for logz.io available.
JustLog brings logging on iOS to the next level. It supports console, file and remote Logstash logging via TCP socket with no effort. Support for logz.io available.

JustLog JustLog takes logging on iOS to the next level. It supports console, file and remote Logstash logging via TCP socket with no effort. Support f

May 1, 2022
Convenient & secure logging during development & release in Swift 3, 4 & 5
Convenient & secure logging during development & release in Swift 3, 4 & 5

Colorful, flexible, lightweight logging for Swift 3, Swift 4 & Swift 5. Great for development & release with support for Console, File & cloud platfor

May 20, 2022
CleanroomLogger provides an extensible Swift-based logging API that is simple, lightweight and performant
CleanroomLogger provides an extensible Swift-based logging API that is simple, lightweight and performant

CleanroomLogger CleanroomLogger provides an extensible Swift-based logging API that is simple, lightweight and performant. The API provided by Cleanro

Apr 18, 2022
Willow is a powerful, yet lightweight logging library written in Swift.

Willow Willow is a powerful, yet lightweight logging library written in Swift. Features Requirements Migration Guides Communication Installation Cocoa

May 3, 2022
Swift Logging Utility for Xcode & Google Docs
Swift Logging Utility for Xcode & Google Docs

QorumLogs Swift Logging Utility in Xcode & Google Docs

May 11, 2022
A simple Swift package for measuring and reporting the time taken for operations

Duration A simple Swift package for measuring and reporting the time taken for operations. It is derived from a version for Playgrounds that I blogged

Feb 18, 2022
A lightweight logging framework for Swift

HeliumLogger Provides a lightweight logging implementation for Swift which logs to standard output. Features Logs output to stdout by default. You can

Mar 23, 2022
A lightweight logging framework for Swift

HeliumLogger Provides a lightweight logging implementation for Swift which logs to standard output. Features Logs output to stdout by default. You can

Mar 23, 2022
TraceLog is a highly configurable, flexible, portable, and simple to use debug logging system for Swift and Objective-C applications running on Linux, macOS, iOS, watchOS, and tvOS.

Please star this github repository to stay up to date. TraceLog Introduction TraceLog is a highly configurable, flexible, portable, and simple to use

May 21, 2022
A flexible logging library written in Swift

Puppy Puppy is a flexible logging library written in Swift ?? It supports multiple transports(console, file, syslog, and oslog) as loggers. It not onl

Apr 30, 2022
An extensible logging framework for Swift
An extensible logging framework for Swift

Log is a powerful logging framework that provides built-in themes and formatters, and a nice API to define your owns. Get the most out of Log by insta

Apr 19, 2022