I have a struct which represents a bitmap image in RGBA form. That struct has properties for each of the color channels, red, blue and green.
I'm trying to build an image filter which adjusts a particular color level. This version works fine, but clearly the pixel.COLOR property is hard coded.
func boostColor(inputColor: String) -> UIImage {
let avgColor = "avg" + inputColor
// let color = inputColor.lowercaseString // plan to use this to set the property
for y in 0..<self.inputRGBA.height {
for x in 0..<self.inputRGBA.width {
let index = y * self.inputRGBA.width + x
var pixel = self.inputRGBA.pixels[index]
// see how far this pixel's chosen color varies from the average
let colorDiff = Int(pixel.red) - Int(self.pixelColorAverages[avgColor]!)
// if less than average red,
if(colorDiff>0){
pixel.red = UInt8( max(0,min(255,Int(self.pixelColorAverages[avgColor]!) + colorDiff*100 ) ) )
// write the adjusted pixel back to the image object
self.inputRGBA.pixels[index] = pixel
}
}
}
// write the filtered RGBA image to a UIImage
return self.inputRGBA.toUIImage()!
}
This loop's function takes in a string value of either "red", "blue" or "green". What I would like to do is replace instances of
pixel.red
with
pixel.[ONE OF THE INPUT COLORS]
Thanks!
(This is an academic playground project. I realize I'm probably re-inventing the wheel by building a color filter. It isn't the color filter itself that I'm interested in, but how to solve this property problem in Swift.)
Here is the struct:
public struct Pixel {
public var value: UInt32
public var red: UInt8 {
get {
return UInt8(value & 0xFF)
}
set {
value = UInt32(newValue) | (value & 0xFFFFFF00)
}
}
public var green: UInt8 {
get {
return UInt8((value >> 8) & 0xFF)
}
set {
value = (UInt32(newValue) << 8) | (value & 0xFFFF00FF)
}
}
public var blue: UInt8 {
get {
return UInt8((value >> 16) & 0xFF)
}
set {
value = (UInt32(newValue) << 16) | (value & 0xFF00FFFF)
}
}
public var alpha: UInt8 {
get {
return UInt8((value >> 24) & 0xFF)
}
set {
value = (UInt32(newValue) << 24) | (value & 0x00FFFFFF)
}
}
}
Implementing Key Value Coding is possible with reflecting but it is very un-Swift. In your case it is also just a bad idea since there are much more powerful and useful alternatives.
I would go for an OptionSetType since there are only a fixed number of possibilities (RGBA). An enum would be fine too but an OptionSetType has the extra benefit of being a "set". So you can choose to alter RGB and not A in a very convenient way.
interesting read on OptionSetType
This is an enum to store the rawValues for the OptionSetType. Can be used on it's own.
public enum RGBAColor : Int, CustomStringConvertible {
case Red = 1, Green = 2, Blue = 4, Alpha = 8
public var description : String { // if you still want to have a String value for each color
var shift = 0
while (rawValue >> shift != 1) { shift++ }
return ["Red","Green","Blue","Alpha"][shift]
}
}
This is the OptionSetType. I create snippets of these kind of structures and copy / paste / modify them when needed. No need to reinvent the wheel when it will always be the same pattern.
public struct RGBAColors : OptionSetType, CustomStringConvertible {
public let rawValue : Int
public init(rawValue:Int) { self.rawValue = rawValue}
private init(_ color:RGBAColor) { self.rawValue = color.rawValue }
static let Red = RGBAColors(RGBAColor.Red)
static let Green = RGBAColors(RGBAColor.Green)
static let Blue = RGBAColors(RGBAColor.Blue)
static let Alpha = RGBAColors(RGBAColor.Alpha)
public var description : String {
var result = ""
var shift = 0
while let currentcolor = RGBAColor(rawValue: 1 << shift++){
if self.contains(RGBAColors(currentcolor)){
result += (result.characters.count == 0) ? "\(currentcolor)" : ",\(currentcolor)"
}
}
return "[\(result)]"
}
}
Now you can add a function to your Pixel struct that will return the color value based on an enum case. You can also choose to pass the OptionSetType directly to this function.
public struct Pixel {
...
public func getValueForColor(color:RGBAColor) -> UInt8 {
switch color {
case .Red : return self.red
case .Green : return self.green
case .Blue : return self.blue
case .Alpha : return self.alpha
}
}
}
This is just a control flow function. You can now do different things based on which color that needs to be altered. (or apply the same to all)
This is also the only reason to choose for an OptionSetType, if you don't need this, just go for an enum. Since the OptionSetType builds on the enum you can always add it later.
func someFuncWithOptions(colors:RGBAColors) {
if colors.contains(.Red) {
someFunc(.Red)
}
if colors.contains(.Blue) {
someFunc(.Blue)
}
if colors.contains(.Green) {
someFunc(.Green)
}
if colors.contains(.Alpha) {
someFunc(.Alpha)
}
}
This will be your actual function
func someFunc(color:RGBAColor) {
// do something with pixel.getValueForColor(color)
print(color)
}
This will be exposed to other parts of your code. So the actual usage of all this will be really simpel. Just input .SomeColor.
The best thing is that the compiler will warn you if you change all this to CMYK for example. Key Value Coding will never generate warnings, it will just crash.
Because it is a "set" and not per definition one color, you pass a collection of options. [.option1,.option2,...] or you pass nothing []
someFuncWithOptions([.Red]) // red
someFuncWithOptions([.Green,.Red]) // red green
You can also add convenient collections to the OptionSetType. This one will be a set of all RGB colors but without the Alpha channel.
static let RGB : RGBAColors = [.Red,.Green,.Blue]
someFuncWithOptions([.RGB]) // red blue green
One approach would be to add a KVC-like syntax to Swift using Swift's built-in reflection capabilities. You can learn how to do that here, although it's serious overkill for this problem:
http://blog.shiftybit.net/2015/07/kvc-in-swift/
A more narrow and suitable solution would just be to write a function for your struct that takes a String argument, switches over it, and returns the desired value. You'd also want to write another function for your struct that takes a String and a value, and sets the value on your struct.
Examples:
struct Pixel
{
// ... rest of struct definition ...
func getColor(color:String) -> UInt8
{
switch color
{
case "red":
return self.red
case "green":
return self.green
case "blue":
return self.blue
case "alpha":
return self.alpha
}
}
func setColor(color:String, value:UInt8)
{
switch color
{
case "red":
self.red = value
case "green":
self.green = value
case "blue":
self.blue = value
case "alpha":
self.alpha = value
}
}
}
If you wanted, you could take it a step further and use an enum instead of a String for improved clarity and type safety.
If you want to pass the color name as string, why don't you define a subscript for your structure? It's awesome and very flexible.
Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence. You use subscripts to set and retrieve values by index without needing separate methods for setting and retrieval.
struct Pixel {
// ...
subscript(color: String) -> UInt8? {
get {
switch color {
case "red":
return red
case "green":
return green
case "blue":
return blue
case "alpha":
return alpha
default:
return nil
}
}
set {
if newValue != nil {
switch color {
case "red":
red = newValue!
case "green":
green = newValue!
case "blue":
blue = newValue!
case "alpha":
alpha = newValue!
default:
break
}
}
}
}
}
var pixel = Pixel(value: 0)
pixel["red"] = 128
Note that it will fail silently in case a wrong color is set like in pixel["yellow"] = 155. To avoid situations like that you could implement a enum and use it as key.
enum Color {
case Red
case Green
case Blue
case Alpha
}
extension Pixel {
subscript(color: Color) -> UInt8 {
get {
switch color {
case .Red:
return red
case .Green:
return green
case .Blue:
return blue
case .Alpha:
return alpha
}
}
set {
switch color {
case .Red:
red = newValue
case .Green:
green = newValue
case .Blue:
blue = newValue
case .Alpha:
alpha = newValue
}
}
}
}
var pixel = Pixel(value: 0)
pixel[.Red] = 128
Related
I want to create a list of levels with a score required to reach that level. But I'm not sure how best to do it.
For example I tried an enum like this:
enum xpLevels {
case 1 = 0...50
case 2 = 51...100
case 3 = 101...200
}
But this gives me errors saying: "Consecutive declarations on a line must be separated by ';'"
And I'm quite sure I haven't structured this right. Is an enum even the right thing to be using for this? I'd appreciate any help to point me in the right direction.
If you really wanted enums, you might do something like this:
enum xpLevels {
case low = 50
case medium = 100
case high = 200
}
Then, in your code, check if the value is <= low, else <= medium, else it must be "high" ;)
Enums are very unsuitable for this. Try an array instead. For example, you can store:
let levelXps = [0, 50, 100, 200]
Or if you want to write out the level numbers as well:
let levelXps = [0:0, 1:50, 2:100, 3:200].values.sorted()
Then you can have a function that tells you what level it is, given a score:
func level(forScore score: Int) -> Int? {
levelXps.lastIndex(where: { score > $0 })?.advanced(by: 1)
}
This finds the index of the last item in the array that is smaller than the given score, then adds 1 to it. If the score is negative, the function returns nil.
You can create an enumeration with the maximum score for each level as suggested by paulsm4 and declare your enumeration as CaseIterable. Then you can create an initializer to get the corresponding case for the score:
enum Level: Int, CaseIterable {
case one = 50, two = 100, three = 200
}
extension Level {
init(rawValue: Int) {
self = Level.allCases.first { 0...$0.rawValue ~= rawValue } ?? .one
}
}
extension Int {
var level: Level { .init(rawValue: self) }
}
let score = 165
let level = score.level // three
You can also create a custom enumeration of closed ranges. You just need to create a computed property to return each case range:
enum Level: CaseIterable {
case one, two, three, four
}
extension Level: RawRepresentable {
typealias RawValue = ClosedRange<Int>
var rawValue: RawValue {
let range: RawValue
switch self {
case .one: range = 0 ... 50
case .two: range = 51 ... 100
case .three: range = 101 ... 200
case .four: range = 201 ... .max
}
return range
}
init?(rawValue: RawValue) {
guard let level = Level.allCases.first(where: { $0.rawValue == rawValue }) else { return nil }
self = level
}
init(score: Int) {
self = Level.allCases.first { $0.rawValue ~= score } ?? .one
}
}
extension Int {
var level: Level { .init(score: self) }
}
let score = 76
let level = score.level // two
I am trying to initialize a deck of cards. I have card attributes in my card struct. My approach is to try and create an array of "enum states", then iterate through those to initialize each card. I am having trouble doing so.
Game Class
import Foundation
struct Set{
var cards = [Card]()
init(){
let properties : [Any] =
[cardShape.self, cardColor.self, cardNumber.self, cardShading.self]
for prop in properties{
// Not really sure how to iterate through this array...
// Ideally it would be something like this.
// Iterate through array, for property in array,
// card.add(property)
}
}
}
Card Class
import UIKit
import Foundation
struct Card{
var attributes : properties = properties()
mutating func addProperty(value : Property){
if value is cardShape{
attributes.shape = value as! cardShape
} else if value is cardColor{
attributes.color = value as! cardColor
} else if value is cardNumber{
attributes.number = value as! cardNumber
}else if value is cardShading{
attributes.shading = value as! cardShading
}else{
print("error")
}
}
}
protocol Property{
static var allValues : [Property] {get}
}
struct properties{
var shape : cardShape = cardShape.none
var color : cardColor = cardColor.none
var number : cardNumber = cardNumber.none
var shading : cardShading = cardShading.none
}
enum cardShape : String,Property{
case Square = "■"
case Triangle = "▲"
case Circle = "●"
case none
static var allValues : [Property]{ return [cardShape.Square,cardShape.Triangle,cardShape.Circle]}
}
enum cardColor:Property {
case Red
case Purple
case Green
case none
static var allValues : [Property] {return [cardColor.Red,cardColor.Purple,cardColor.Green]}
}
enum cardNumber : Int,Property{
case One = 1
case Two = 2
case Three = 3
case none
static var allValues : [Property] {return [cardNumber.One,cardNumber.Two,cardNumber.Three]}
}
enum cardShading: Property {
case Solid
case Striped
case Outlined
case none
static var allValues : [Property] {return [cardShading.Solid,cardShading.Striped,cardShading.Outlined]}
}
So to summarize, my main issue is trying to create an array of enums, then cycling through the enum states to initialize a card with specific attribute states.
You will want to make sure you cover all combinations of attributes and make sure each card has one of each of the four types of attributes. I would suggest using nested loops:
for shape in cardShape.allValues {
for color in cardColor.allValues {
for number in cardNumber.allValues {
for shading in cardShading.allValues {
var card = Card()
card.addProperty(shape)
card.addProperty(color)
card.addProperty(number)
card.addProperty(shading)
cards.append(card)
}
}
}
}
I believe your Card struct is a bit too complex. If you change your representation, it will be easier to create the cards.
Have your card represent the different attributes as their own property:
struct Card {
let shape: CardShape
let color: CardColor
let number: CardNumber
let shading: CardShading
}
Then use nested loops to create your cards:
for shape in CardShape.allValues {
for color in CardColor.allValues {
for number in CardNumber.allValues {
for shading in CardShading.allValues {
cards.append(Card(shape: shape, color: color, number: number, shading: shading))
}
}
}
}
Notes:
Your enums should start with uppercase characters, and your enum values should start with lowercase characters.
Using separate properties for each attribute will make it much easier to check for matching attributes between cards.
You get an initializer by default that initializes all properties. By initializing them with nested loops, you will be able to create all possible cards.
Change your allValues properties to return arrays of the specific attribute type (for example [CardShape]).
Alternate Answer:
Instead of using nested arrays, you could use MartinR's combinations function to create the list of combinations of the properties. Adding an init to Card that takes [Property], you can create the cards in two lines of code:
struct Card {
var shape = CardShape.none
var color = CardColor.none
var number = CardNumber.none
var shading = CardShading.none
init(properties: [Property]) {
for property in properties {
switch property {
case let shape as CardShape:
self.shape = shape
case let color as CardColor:
self.color = color
case let number as CardNumber:
self.number = number
case let shading as CardShading:
self.shading = shading
default:
break
}
}
}
}
// https://stackoverflow.com/a/45136672/1630618
func combinations<T>(options: [[T]]) -> AnySequence<[T]> {
guard let lastOption = options.last else {
return AnySequence(CollectionOfOne([]))
}
let headCombinations = combinations(options: Array(options.dropLast()))
return AnySequence(headCombinations.lazy.flatMap { head in
lastOption.lazy.map { head + [$0] }
})
}
struct SetGame {
let cards: [Card]
init(){
let properties: [Property.Type] = [CardShape.self, CardColor.self, CardNumber.self, CardShading.self]
cards = combinations(options: properties.map { $0.allValues }).map(Card.init)
}
}
How this works:
properties.map { $0.allValues } calls allValues on each item of the properties array creating an [[Property]] with [[.square, .triangle, .circle], [.red, .purple, .green], [.one, .two, .three], [.solid, .striped, .outlined]]
This is passed to combinations which creates a sequence with all 81 combinations of these properties: [[.square, .red, .one, .solid], ..., [.circle, .green, .three, .outlined]].
map is run on this sequence to call Card.init with each combination which results in an [Card] with 81 cards.
I am quite new to Swift and I am learning about structs. However, I have a problem which might sound obvious, but I'm not sure how to do it. I am doing all this in the playground.
I have a struct called Colour, where I create an RGB colour type. I want to access its variables (e.g. by doing yellow.red which will read and write the variable to find the value of red in the colour yellow).
struct Colour {
var red: Int
var blue: Int
var green: Int
var rgb: [Int] // <- I don't want to have this variable, I want to make the struct Colour be this array
init(red: Int, green: Int, blue: Int) {
self.red = red
self.green = green
self.blue = blue
rgb = [red, green, blue]
}
}
Call:
let red = Colour(red: 255, green: 0, blue: 0) // Colour
red.red // 255
red.green // 0
red.blue // 0
red // Colour
red.rgb // [255, 0, 0]
When I access red, I want it to automatically return the value of red.rgb, without the variable.
So how can I call red and return an Array with the value [255, 0, 0]?
Notes:
A get or set cannot be implemented
I cannot use Colour as a variable, as I need initialisation
return keyword cannot be used, as structs don't work in this way
Edit
Sorry for not making this clear enough. I was looking to return a [Int], but it is clearly not worth what I was originally trying.
The solutions with the protocols definitely work if you want to return a string, which is why I have accepted an answer.
Edit 2
We now have a working answer using type alias!
Alternatively, you can define a typealias Colour. This might be a little more efficient, but perhaps not as type safe.
See code:
typealias Colour = [Int]
extension Array where Element == Int {
init(red: Int, green: Int, blue: Int) {
self = [red, green, blue]
}
var red: Int { return self.count > 0 ? self[0] : 0 }
var green: Int { return self.count > 1 ? self[1] : 0 }
var blue: Int { return self.count > 2 ? self[2] : 0 }
}
Example Usage:
let red = Colour(red: 255, green: 0, blue: 0) // Colour
red.red // 255
red.green // 0
red.blue // 0
red // [255, 0, 0]
red is a Colour. There's nothing you can do to change that. Nothing you do can make red act directly as a [Int] containing the red, green, and blue components.
There are different things you can do, depending on what your actual needs are. For example, if you just want it to act like an [Int] for the sake of printing like [255, 0, 0], then you can override var description: String and conform to CustomStringConvertible.
The sort of feature you're looking for is like C++'s user-defined conversion operators. These can be really cool, but can also easily lead to very unclear code. Swift opts for explicitly expressing such conversions, for the sake of clarity.
Swift has a Protocol called CustomDebugStringConvertible that should accomplish what you're looking for. After declaring that your struct adopts that Protocol, just implement the debugDescription variable in your code.
See update code:
struct Colour: CustomDebugStringConvertible {
var red: Int
var green: Int
var blue: Int
var debugDescription: String {
return "\(array)"
}
var array: [Int] {
return [red, green, blue]
}
init(red: Int, green: Int, blue: Int) {
self.red = red
self.green = green
self.blue = blue
}
}
Example usage:
let red = Colour(red: 255, green: 0, blue: 0) // Colour
red.red // 255
red.green // 0
red.blue // 0
red // "[255, 0, 0]"
red.array // [255, 0, 0]
I would suggest adding a function such as toArray()
That could look something like this:
struct Colour {
var red: Int
var blue: Int
var green: Int
init(red: Int, green: Int, blue: Int) {
self.red = red
self.green = green
self.blue = blue
}
func toArray() -> [Int] {
return [self.red, self.green, self.blue]
}
}
Then, in your code, you can just use let rgbArray = MyColour.toArray()
Also, I would advise against storing the same underlying data twice, such as with your rgb variable. If you change the Colour.red variable, that would mean your Colour.rgb value is not updated with that new value automatically and you suddenly get back values that you did not expect. With the function approach, you won't have that problem.
If you want to make the Colour type a custom collection, enabling you to use it like an Array but make it type-safe at the same time, you can create a custom struct and make it conform to Collection. You can create an RGB enum that can be used for indexing the custom collection and a failable initializer that ensures you can only create a Colour instance with valid RGB values.
struct Colour: Collection, RandomAccessCollection {
// Custom enum used for indexing Colour
enum RGB: Int, Hashable, Comparable, Strideable {
case red, green ,blue
// Find the last existing rawValue, assumes that the first case has rawValue 0 and that rawValues are incremented by 1
static let maxRawValue: RGB.RawValue = {
var maxRawVal = 0
while RGB(rawValue: maxRawVal) != nil {
maxRawVal += 1
}
return maxRawVal
}()
static let rawValues: [RGB.RawValue] = {
var rawValues = [RGB.RawValue]()
var currentRawValue = 0
while RGB(rawValue: currentRawValue) != nil {
rawValues.append(currentRawValue)
currentRawValue += 1
}
return rawValues
}()
static func <(lhs: RGB, rhs: RGB) -> Bool {
return lhs.rawValue < rhs.rawValue
}
typealias Stride = Int
func distance(to other: RGB) -> RGB.Stride {
return self.rawValue - other.rawValue
}
func advanced(by n: RGB.Stride) -> RGB {
return RGB(rawValue: (self.rawValue+n)%RGB.maxRawValue)!
}
}
typealias Element = Int
typealias Index = RGB
//Private backing Array
private var components:[Element] = Array<Element>.init(repeating: Element.init(), count: RGB.rawValues.count)
var startIndex: Colour.Index {
return RGB(rawValue: components.startIndex)!
}
var endIndex: Colour.Index {
return RGB(rawValue: components.endIndex)!
}
subscript (position: Index) -> Element {
get {
return components[position.rawValue]
}
set {
components[position.rawValue] = newValue
}
}
func index(after i: Index) -> Index {
return Index(rawValue: components.index(after: i.rawValue))!
}
private init(){}
//Failable initializer that makes sure only a 3 element Array can be used as an input and that each element is in the valid RGB color code range
init?<C:Collection>(_ collection:C) where C.Element == Element, C.Index == Index.RawValue {
guard collection.indices.map({$0}) == RGB.rawValues else {return nil}
for (index, element) in collection.enumerated() {
guard element <= 255 && element >= 0 else {return nil}
self.components[index] = element
}
}
}
Then you can use your custom collection safely:
let red = Colour([255,0,0]) // Colour
let invalidColour = Colour([255]) // nil
let invalidColour2 = Colour([255,2,3,4]) // nil
let invalidColour3 = Colour([255,-1,256]) // nil
let randomColour = Colour([1,5,231]) // Colour
// you can use the RGB cases to access the respective values in the collection
randomColour?[.red] // 1
Sorry if this is a stupid question but I'm wondering if there's a way in Swift to create a type that exclusively holds numbers that are strictly greater than zero and where the "positiveness" of the values is enforced at compile time.
For example, can I create somehow write code like
func divide(x: PositiveNumber, y: PositiveNumber){
return x / y
}
such that
divide(1, 3)
works but
divide(1, 0)
won't compile?
The closest thing I could come up with was a struct with only one fallible initializer such that the type has either a positive value or is nil:
struct PositiveNumber {
let value: Float
init?(value: Float){
if value > 0 {
self.value = value
} else {
return nil
}
}
}
func / (left: PositiveNumber, right: PositiveNumber) -> Float {
return left.value / right.value
}
func divide(x: PositiveNumber?, y: PositiveNumber?) -> Float? {
if let x = x, y = y {
return x / y
}
return nil
}
let x1 = PositiveNumber(value: 1)
let y1 = PositiveNumber(value: 3)
let x2 = PositiveNumber(value: -1)
let y2 = PositiveNumber(value: 0)
divide(x1, y: y1)! // .333
divide(x2, y: y2)! // runtime error
That's not terrible but we still have to deal with a lot of optional handling/unwrapping. I'm asking this question because I have many places in my code where I need to check that a value is not zero and I'm curious if there's a way to remove that code and let the compiler handle it. The struct-based solution requires pretty much the same amount of code.
Number Type build on Float
This gist is contains a Struct that conforms to pretty much everything Float conforms too. It is just a vanilla copy of Float, change it to your liking.
Have you considered a custom operator?
infix operator /+ { associativity left precedence 150 }
func /+(lhs:Float,rhs:Float) -> Float? {
guard rhs > 0 else {
return nil
}
return lhs / rhs
}
let test = 2 /+ -1 // nil
let test2 = 2 /+ 1 // 2
let test3 = 2 /+ 1 + 2 // warning
It doesn't really matter if you let it return an optional, or an enum value, or different protocols. You will have to handle the return. But this way you get compiler warnings.
Limited Number Type with just an operator to handle divisions:
You could change math altogether and create a PositiveNumber Type that returns NaN when dividing by a value less than Zero.
public struct PositiveFloat {
public var value: Float
/// Create an instance initialized to zero.
public init() {
self.value = 0
}
/// Create an instance initialized to `value`.
public init(_ value: Float) {
self.value = value
}
public init(_ value: PositiveFloat) {
self.value = value.value
}
}
extension Float {
public var positive : PositiveFloat {
return PositiveFloat(self)
}
}
public func /(lhs:Float,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs / rhs.value
} else {
return Float.NaN
}
}
public func /(lhs:PositiveFloat,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs.value / rhs.value
} else {
return Float.NaN
}
}
let testNormal : Float = 10
let testFloat : Float = -5
let test = testFloat / testNormal.positive
if test.isNaN {
// do stuff
}
I'm writing a command line tool with Swift and I'm having trouble displaying colors in my shell. I'm using the following code:
println("\033[31;32mhey\033[39;39m")
or even
NSFileHandle.fileHandleWithStandardOutput().writeData("\033[31;32mhey\033[39;39m".dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)!)
It works when I use a simple echo in php (the text is displayed in green) but is there a reason it doesn't work in a Swift command line tool?
Thanks!
Swift has built in unicode support. This invalidates using of back slash. So that I use color codes with "\u{}" syntax. Here is a println code which works perfectly on terminal.
// \u{001B}[\(attribute code like bold, dim, normal);\(color code)m
// Color codes
// black 30
// red 31
// green 32
// yellow 33
// blue 34
// magenta 35
// cyan 36
// white 37
println("\u{001B}[0;33myellow")
Hope it helps.
Based on #cyt answer, I've written a simple enum with these colors and also overloaded + operator so you can print using that enum.
It's all up on Github, but it's really that simple:
enum ANSIColors: String {
case black = "\u{001B}[0;30m"
case red = "\u{001B}[0;31m"
case green = "\u{001B}[0;32m"
case yellow = "\u{001B}[0;33m"
case blue = "\u{001B}[0;34m"
case magenta = "\u{001B}[0;35m"
case cyan = "\u{001B}[0;36m"
case white = "\u{001B}[0;37m"
case `default` = "\u{001B}[0;0m"
func name() -> String {
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"
}
}
static func all() -> [ANSIColors] {
return [.black, .red, .green, .yellow, .blue, .magenta, .cyan, .white]
}
}
func + (left: ANSIColors, right: String) -> String {
return left.rawValue + right
}
// END
// Demo:
for c in ANSIColors.all() {
print(c + "This is printed in " + c.name())
}
You can use Rainbow if you don't mind using it as a framework.
import Rainbow
print("Red text".red)
print("Yellow background".onYellow)
print("Light green text on white background".lightGreen.onWhite)
https://github.com/onevcat/Rainbow
Combining some of #Diego's answer, you can use Swift's new DefaultStringInterpolation structure to extend this decoration into your string literals–
enum ASCIIColor: String {
case black = "\u{001B}[0;30m"
case red = "\u{001B}[0;31m"
case green = "\u{001B}[0;32m"
case yellow = "\u{001B}[0;33m"
case blue = "\u{001B}[0;34m"
case magenta = "\u{001B}[0;35m"
case cyan = "\u{001B}[0;36m"
case white = "\u{001B}[0;37m"
case `default` = "\u{001B}[0;0m"
}
extension DefaultStringInterpolation {
mutating func appendInterpolation<T: CustomStringConvertible>(_ value: T, color: ASCIIColor) {
appendInterpolation("\(color.rawValue)\(value)\(ASCIIColor.default.rawValue)")
}
}
// USAGE:
// "\("only this string will be green!", color: .green)"
Expanding upon Diego Freniche's answer we can incorporate the functionality of Rainbow, as referenced in Uncharted Works's Answer, without needing to import the framework itself using a simple String extension:
enum ANSIColor: String {
typealias This = ANSIColor
case black = "\u{001B}[0;30m"
case red = "\u{001B}[0;31m"
case green = "\u{001B}[0;32m"
case yellow = "\u{001B}[0;33m"
case blue = "\u{001B}[0;34m"
case magenta = "\u{001B}[0;35m"
case cyan = "\u{001B}[0;36m"
case white = "\u{001B}[0;37m"
case `default` = "\u{001B}[0;0m"
static var values: [This] {
return [.black, .red, .green, .yellow, .blue, .magenta, .cyan, .white, .default]
}
static var names: [This: String] = {
return [
.black: "black",
.red: "red",
.green: "green",
.yellow: "yellow",
.blue: "blue",
.magenta: "magenta",
.cyan: "cyan",
.white: "white",
.default: "default",
]
}
var name: String {
return This.names[self] ?? "unknown"
}
static func + (lhs: This, rhs: String) -> String {
return lhs.rawValue + rhs
}
static func + (lhs: String, rhs: This) -> String {
return lhs + rhs.rawValue
}
}
extension String {
func colored(_ color: ANSIColor) -> String {
return color + self + ANSIColor.default
}
var black: String {
return colored(.black)
}
var red: String {
return colored(.red)
}
var green: String {
return colored(.green)
}
var yellow: String {
return colored(.yellow)
}
var blue: String {
return colored(.blue)
}
var magenta: String {
return colored(.magenta)
}
var cyan: String {
return colored(.cyan)
}
var white: String {
return colored(.white)
}
}
Elegant Solution:
struct Colors {
static let reset = "\u{001B}[0;0m"
static let black = "\u{001B}[0;30m"
static let red = "\u{001B}[0;31m"
static let green = "\u{001B}[0;32m"
static let yellow = "\u{001B}[0;33m"
static let blue = "\u{001B}[0;34m"
static let magenta = "\u{001B}[0;35m"
static let cyan = "\u{001B}[0;36m"
static let white = "\u{001B}[0;37m"
}
Demo
print(Colors.yellow + "Please Enter the Output Directory Name:" + Colors.reset)
or
print(Colors.yellow + "Please " + Colors.blue + "Enter " + Colors.magenta + "the Output Directory Name:" + Colors.reset)