CommandLineToolkit

Форк
0
216 строк · 6.2 Кб
1
/// Terminal ANSI commands
2
enum ANSICommand {
3
    case eraseScreen
4
    case eraseLine
5
    case cursorUp
6
    case sgr([ANSISGRCommand])
7
}
8

9
/// Terminal ANSI Set Graphics Rendition (SGR) commands
10
enum ANSISGRCommand {
11
    /// Set attribute
12
    case attribute(ConsoleAttribute)
13
    /// Traditional foreground color
14
    case foregroundColor(UInt8)
15
    /// Traditional bright foreground color
16
    case brightForegroundColor(UInt8)
17
    /// Palette foreground color
18
    case paletteForegroundColor(UInt8)
19
    /// RGB "true-color" foreground color
20
    case rgbForegroundColor(r: UInt8, g: UInt8, b: UInt8)
21
    /// Keep current foreground color (effective no-op)
22
    case defaultForegroundColor
23
    /// Traditional background color
24
    case backgroundColor(UInt8)
25
    /// Traditional bright background color
26
    case brightBackgroundColor(UInt8)
27
    /// Palette background color
28
    case paletteBackgroundColor(UInt8)
29
    /// RGB "true-color" background color
30
    case rgbBackgroundColor(r: UInt8, g: UInt8, b: UInt8)
31
    /// Keep current background color (effective no-op)
32
    case defaultBackgroundColor
33
}
34

35
extension ConsoleText {
36
    /// Wraps a string in the ANSI codes indicated
37
    /// by the style specification
38
    func terminalStylize() -> String {
39
        return fragments
40
            .map { $0.string.terminalStylize($0.style) }
41
            .joined()
42
    }
43
}
44

45
extension String {
46
    /// Wraps a string in the ANSI codes indicated
47
    /// by the style specification
48
    func terminalStylize(_ style: ConsoleStyle) -> String {
49
        if style.color == nil && style.background == nil && style.attributes.isEmpty {
50
            return self // No style ("plain")
51
        }
52
        return style.ansiCommand.ansi +
53
            self +
54
        ANSICommand.sgr([.attribute(.normal)]).ansi
55
    }
56
}
57

58
// MARK: private
59

60
extension ANSICommand {
61
    /// Converts the command to its ansi code.
62
    fileprivate var ansi: String {
63
        switch self {
64
        case .cursorUp:
65
            return "1A".ansi
66
        case .eraseScreen:
67
            return "2J".ansi
68
        case .eraseLine:
69
            return "2K".ansi
70
        case .sgr(let subcommands):
71
            return (subcommands.map { $0.ansi }.joined(separator: ";") + "m").ansi
72
        }
73
    }
74
}
75

76
extension ANSISGRCommand {
77
    /// Converts the command to its ansi code.
78
    var ansi: String {
79
        switch self {
80
        case let .attribute(attribute):
81
            return "\(attribute.rawValue)"
82
        case let .foregroundColor(c):
83
            return "3\(c)"
84
        case let .brightForegroundColor(c):
85
            return "9\(c)"
86
        case let .paletteForegroundColor(c):
87
            return "38;5;\(c)"
88
        case let .rgbForegroundColor(r, g, b):
89
            return "38;2;\(r);\(g);\(b)"
90
        case .defaultForegroundColor:
91
            return "39"
92
        case let .backgroundColor(c):
93
            return "4\(c)"
94
        case let .brightBackgroundColor(c):
95
            return "10\(c)"
96
        case let .paletteBackgroundColor(c):
97
            return "48;5;\(c)"
98
        case let .rgbBackgroundColor(r, g, b):
99
            return "48;2;\(r);\(g);\(b)"
100
        case .defaultBackgroundColor:
101
            return "49"
102
        }
103
    }
104
}
105

106
/// This type exists for the sole purpose of encapsulating
107
/// the logic for distinguishing between "foreground" and "background"
108
/// encodings of otherwise identically-specified colors.
109
enum ANSISGRColorSpec {
110
    case traditional(UInt8)
111
    case bright(UInt8)
112
    case palette(UInt8)
113
    case rgb(r: UInt8, g: UInt8, b: UInt8)
114
    case `default`
115
}
116

117
extension ConsoleColor {
118
    /// Converts the color to the corresponding SGR color spec
119
    var ansiSpec: ANSISGRColorSpec {
120
        switch self {
121
        case .black:
122
            return .traditional(0)
123
        case .red:
124
            return .traditional(1)
125
        case .green:
126
            return .traditional(2)
127
        case .yellow:
128
            return .traditional(3)
129
        case .blue:
130
            return .traditional(4)
131
        case .magenta:
132
            return .traditional(5)
133
        case .cyan:
134
            return .traditional(6)
135
        case .white:
136
            return .traditional(7)
137
        case .brightBlack:
138
            return .bright(0)
139
        case .brightRed:
140
            return .bright(1)
141
        case .brightGreen:
142
            return .bright(2)
143
        case .brightYellow:
144
            return .bright(3)
145
        case .brightBlue:
146
            return .bright(4)
147
        case .brightMagenta:
148
            return .bright(5)
149
        case .brightCyan:
150
            return .bright(6)
151
        case .brightWhite:
152
            return .bright(7)
153
        case let .palette(p):
154
            return .palette(p)
155
        case let .custom(r, g, b):
156
            return .rgb(r: r, g: g, b: b)
157
        }
158
    }
159
}
160

161
extension ANSISGRColorSpec {
162
    /// Convert the color spec to an SGR command
163
    var foregroundAnsiCommand: ANSISGRCommand {
164
        switch self {
165
        case let .traditional(c):
166
            return .foregroundColor(c)
167
        case let .bright(c):
168
            return .brightForegroundColor(c)
169
        case let .palette(c):
170
            return .paletteForegroundColor(c)
171
        case let .rgb(r, g, b):
172
            return .rgbForegroundColor(r: r, g: g, b: b)
173
        case .`default`:
174
            return .defaultForegroundColor
175
        }
176
    }
177

178
    var backgroundAnsiCommand: ANSISGRCommand {
179
        switch self {
180
        case let .traditional(c):
181
            return .backgroundColor(c)
182
        case let .bright(c):
183
            return .brightBackgroundColor(c)
184
        case let .palette(c):
185
            return .paletteBackgroundColor(c)
186
        case let .rgb(r, g, b):
187
            return .rgbBackgroundColor(r: r, g: g, b: b)
188
        case .`default`:
189
            return .defaultBackgroundColor
190
        }
191
    }
192
}
193

194
extension ConsoleStyle {
195
    /// The ANSI command for this console style.
196
    var ansiCommand: ANSICommand {
197
        var commands: [ANSISGRCommand] = []
198

199
        if let color = color {
200
            commands.append(color.ansiSpec.foregroundAnsiCommand)
201
        }
202
        if let background = background {
203
            commands.append(background.ansiSpec.backgroundAnsiCommand)
204
        }
205
        commands += attributes.map(ANSISGRCommand.attribute)
206

207
        return .sgr(commands)
208
    }
209
}
210

211
extension String {
212
    /// Converts a String to a full ANSI command.
213
    fileprivate var ansi: String {
214
        return .CSI + self
215
    }
216
}
217

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.