CommandLineToolkit

Форк
0
/
ConsoleText.swift 
174 строки · 5.2 Кб
1
extension String {
2
    /// Converts this `String` to `ConsoleText`.
3
    ///
4
    ///     console.output("Hello, " + "world!".consoleText(color: .green))
5
    ///
6
    /// See `ConsoleStyle` for more information.
7
    func consoleText(_ style: ConsoleStyle = .plain) -> ConsoleText {
8
        return [ConsoleTextFragment(string: self, style: style)]
9
    }
10

11
    /// Converts this `String` to `ConsoleText`.
12
    ///
13
    ///     console.output("Hello, " + "world!".consoleText(color: .green))
14
    ///
15
    /// See `ConsoleStyle` for more information.
16
    func consoleText(color: ConsoleColor? = nil, background: ConsoleColor? = nil, attributes: [ConsoleAttribute] = []) -> ConsoleText {
17
        let style = ConsoleStyle(color: color, background: background, attributes: attributes)
18
        return consoleText(style)
19
    }
20
}
21

22
/// A collection of `ConsoleTextFragment`s. Represents stylized text that can be outputted
23
/// to a `Console`.
24
///
25
///     let text: ConsoleText = "Hello, " + "world".consoleText(color: .green)
26
///
27
struct ConsoleText: RandomAccessCollection, ExpressibleByArrayLiteral, ExpressibleByStringLiteral, CustomStringConvertible, Equatable {
28
    /// See `Collection`.
29
    var startIndex: Int {
30
        return fragments.startIndex
31
    }
32

33
    /// See `Collection`.
34
    var endIndex: Int {
35
        return fragments.endIndex
36
    }
37

38
    /// See `Collection`.
39
    func index(after i: Int) -> Int {
40
        return i + 1
41
    }
42

43
    /// See `CustomStringConvertible`.
44
    var description: String {
45
        return fragments.map { $0.string }.joined()
46
    }
47

48
    /// See `ExpressibleByArrayLiteral`.
49
    init(arrayLiteral elements: ConsoleTextFragment...) {
50
        self.fragments = elements
51
    }
52

53
    /// See `ExpressibleByStringLiteral`.
54
    init(stringLiteral string: String) {
55
        if string.isEmpty {
56
            self.fragments = []
57
        } else {
58
            self.fragments = [.init(string: string)]
59
        }
60
    }
61

62
    /// One or more `ConsoleTextFragment`s making up this `ConsoleText.
63
    var fragments: [ConsoleTextFragment]
64

65
    /// Creates a new `ConsoleText`.
66
    init(fragments: [ConsoleTextFragment]) {
67
        self.fragments = fragments
68
    }
69

70
    /// See `Collection`.
71
    subscript(position: Int) -> ConsoleTextFragment {
72
        return fragments[position]
73
    }
74

75
    /// `\n` character with plain styling.
76
    static let newLine: ConsoleText = "\n"
77
}
78

79
extension ConsoleText {
80
    /// Trims text to specific length
81
    /// - Parameter length: line length
82
    /// - Returns: trimmed text
83
    func trimmed(to length: Int) -> Self {
84
        var remainingLength = length
85
        let newFragments: [ConsoleTextFragment] = fragments.compactMap { fragment in
86
            if fragment.string.count > remainingLength {
87
                if remainingLength > 0 {
88
                    let stringPart = String(fragment.string.prefix(remainingLength - 1))
89
                    remainingLength = 0
90
                    return .init(string: stringPart + "…", style: fragment.style)
91
                } else {
92
                    return nil
93
                }
94
            } else {
95
                remainingLength -= fragment.string.count
96
                return fragment
97
            }
98
        }
99

100
        return .init(fragments: newFragments)
101
    }
102
}
103

104
// MARK: Operators
105

106
extension ConsoleText {
107
    /// Appends a `ConsoleText` to another `ConsoleText`.
108
    ///
109
    ///     let text: ConsoleText = "Hello, " + "world!"
110
    ///
111
    static func +(lhs: ConsoleText, rhs: ConsoleText) -> ConsoleText {
112
        return ConsoleText(fragments: lhs.fragments + rhs.fragments)
113
    }
114

115
    /// Appends a `ConsoleText` to another `ConsoleText` in-place.
116
    ///
117
    ///     var text: ConsoleText = "Hello, "
118
    ///     text += "world!"
119
    ///
120
    static func +=(lhs: inout ConsoleText, rhs: ConsoleText) {
121
        lhs = lhs + rhs
122
    }
123
}
124

125
extension ConsoleText: ExpressibleByStringInterpolation {
126
    init(stringInterpolation: StringInterpolation) {
127
        self.fragments = stringInterpolation.fragments
128
    }
129

130
    struct StringInterpolation: StringInterpolationProtocol {
131
        var fragments: [ConsoleTextFragment]
132

133
        init(literalCapacity: Int, interpolationCount: Int) {
134
            self.fragments = []
135
            self.fragments.reserveCapacity(literalCapacity)
136
        }
137

138
        mutating func appendLiteral(_ literal: String) {
139
            self.fragments.append(.init(string: literal))
140
        }
141

142
        mutating func appendInterpolation(
143
            _ value: String,
144
            style: ConsoleStyle = .plain
145
        ) {
146
            self.fragments.append(.init(string: value, style: style))
147
        }
148
        
149
        mutating func appendInterpolation(
150
            _ value: String,
151
            color: ConsoleColor?,
152
            background: ConsoleColor? = nil,
153
            attributes: [ConsoleAttribute] = []
154
        ) {
155
            self.fragments.append(.init(string: value, style: .init(
156
                color: color,
157
                background: background,
158
                attributes: attributes
159
            )))
160
        }
161

162
        mutating func appendInterpolation(
163
            _ value: ConsoleTextFragment
164
        ) {
165
            self.fragments.append(value)
166
        }
167

168
        mutating func appendInterpolation(
169
            _ value: ConsoleText
170
        ) {
171
            self.fragments.append(contentsOf: value.fragments)
172
        }
173
    }
174
}
175

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

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

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

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