Вывод цвета с помощью инструмента командной строки Swift

Я пишу инструмент командной строки со Swift, и у меня возникают проблемы с отображением цветов в моей оболочке. Я использую следующий код:

println("\033[31;32mhey\033[39;39m")

или даже

NSFileHandle.fileHandleWithStandardOutput().writeData("\033[31;32mhey\033[39;39m".dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)!)

Это работает, когда я использую простое эхо в php (текст отображается зеленым цветом), но есть ли причина, по которой он не работает в инструменте командной строки Swift?

Спасибо!

7 ответов

Решение

Swift имеет встроенную поддержку Unicode. Это делает недействительным использование обратной косой черты. Так что я использую цветовые коды с синтаксисом "\u{}". Вот код println, который отлично работает на терминале.

// \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")

Надеюсь, поможет.

Основываясь на ответе @cyt, я написал простое перечисление с этими цветами, а также перегружен + оператор, так что вы можете печатать, используя это перечисление.

Это все на Github, но это действительно так просто:

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"

    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"
        }
    }

    static func all() -> [ANSIColors] {
        return [.black, .red, .green, .yellow, .blue, .magenta, .cyan, .white]
    }
}

func + (let left: ANSIColors, let right: String) -> String {
    return left.rawValue + right
}

// END


// Demo:

for c in ANSIColors.all() {
    println(c + "This is printed in " + c.name())
}

Вы можете использовать Rainbow, если вы не против использовать его в качестве основы.

import Rainbow
print("Red text".red)
print("Yellow background".onYellow)
print("Light green text on white background".lightGreen.onWhite)

https://github.com/onevcat/Rainbow

Комбинируя некоторые из ответов @Diego, вы можете использовать новый Swift DefaultStringInterpolation структура, чтобы расширить это украшение до ваших строковых литералов -

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)"

Вот мое решение:

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"
}

Демо

print(Colors.yellow + "Please Enter the Output Directory Name:" + Colors.reset)

или же

print(Colors.yellow + "Please " + Colors.blue + "Enter " + Colors.magenta + "the Output Directory Name:" + Colors.reset)

Расширяя ответ Диего Френиша, мы можем включить функциональность Rainbow, как указано в ответе Uncharted Works, без необходимости импортировать саму структуру с помощью простогоString расширение:

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)
    }

}

Используйте шрифт из ColoredConsole плюс расширение дляString.

  1. Установите ColoredConsole-Bold.ttf
  2. В Xcode установите для вывода на консоль шрифт «Цветная консоль, полужирный».
  3. Добавьте это расширение в String в свой проект (на основе jjrscott ).
      
import Foundation

public extension String {
    var consoleColor: ColoredConsoleString {
        ColoredConsoleString(self)
    }
}

public class ColoredConsoleString {
    var string: String
    
    public enum ColorSelectors: String {
        case red = "\u{fe06}"
        case green = "\u{fe07}"
        case brown = "\u{fe08}"
        case teal = "\u{fe09}"
        case purple = "\u{fe0a}"
    }
    
    init(_ str: String) {
        string = str
    }
    
    public var teal: String {
        wrappedString(color: .teal, string)
    }
    
    public var purple: String {
        wrappedString(color: .purple, string)
    }
    
    public var red: String {
        wrappedString(color: .red, string)
    }
    
    public var green: String {
        wrappedString(color: .green, string)
    }
    
    public var brown: String {
        wrappedString(color: .brown, string)
    }
    
    private func wrappedString(color: ColorSelectors, _ string: String) -> String {
        Array(string).map({ "\($0)\(color.rawValue)"}).joined()
    }
}

  1. Теперь вы можете вывести на консоль строки трех разных цветов:
          print("red".consoleColor.red)
    print("green!".consoleColor.green)
    print("purple".consoleColor.purple)
    print("brown".consoleColor.brown)
    print("teal".consoleColor.teal)

Работает с Xcode 14.3 и, возможно, более старыми версиями.

  • Примечание.po print("red".consoleColor.red)на снимке экрана сообщает отладчику Xcode (lldb) вычислить и распечатать выражение. Больше о poздесь
Другие вопросы по тегам