@@ -25,40 +25,62 @@ public struct Trivia {
2525 self . pieces = Array ( pieces)
2626 }
2727
28- /// Creates Trivia with no pieces.
29- public static var zero : Trivia {
30- return Trivia ( pieces: [ ] )
31- }
32-
3328 /// Whether the Trivia contains no pieces.
3429 public var isEmpty : Bool {
3530 pieces. isEmpty
3631 }
3732
33+ public var sourceLength : SourceLength {
34+ return pieces. map ( { $0. sourceLength } ) . reduce ( . zero, + )
35+ }
36+
37+ /// Get the byteSize of this trivia
38+ public var byteSize : Int {
39+ return sourceLength. utf8Length
40+ }
41+
3842 /// Creates a new `Trivia` by appending the provided `TriviaPiece` to the end.
3943 public func appending( _ piece: TriviaPiece ) -> Trivia {
4044 var copy = pieces
4145 copy. append ( piece)
4246 return Trivia ( pieces: copy)
4347 }
4448
45- public var sourceLength : SourceLength {
46- return pieces. map ( { $0. sourceLength } ) . reduce ( . zero, + )
49+ /// Creates a new `Trivia` by appending the given trivia to the end.
50+ public func appending( _ trivia: Trivia ) -> Trivia {
51+ var copy = pieces
52+ copy. append ( contentsOf: trivia. pieces)
53+ return Trivia ( pieces: copy)
4754 }
4855
49- /// Get the byteSize of this trivia
50- public var byteSize : Int {
51- return sourceLength. utf8Length
56+ /// Creates a new `Trivia` by merging in the given trivia. Only includes one
57+ /// copy of a common prefix of `self` and `trivia`.
58+ public func merging( _ trivia: Trivia ) -> Trivia {
59+ let lhs = self . decomposed
60+ let rhs = trivia. decomposed
61+ for infixLength in ( 0 ... Swift . min ( lhs. count, rhs. count) ) . reversed ( ) {
62+ if lhs. suffix ( infixLength) == rhs. suffix ( infixLength) {
63+ return lhs. appending ( Trivia ( pieces: Array ( rhs. dropFirst ( infixLength) ) ) )
64+ }
65+ }
66+ return lhs. appending ( rhs)
67+ }
68+
69+ /// Creates a new `Trivia` by merging the leading and trailing `Trivia`
70+ /// of `triviaOf` into the end of `self`. Only includes one copy of any
71+ /// common prefixes.
72+ public func merging< T: SyntaxProtocol > ( triviaOf node: T ) -> Trivia {
73+ return merging ( node. leadingTrivia) . merging ( node. trailingTrivia)
5274 }
5375
5476 /// Concatenates two collections of `Trivia` into one collection.
55- public static func + ( lhs: Trivia , rhs: Trivia ) -> Trivia {
56- return Trivia ( pieces : lhs. pieces + rhs. pieces )
77+ public static func + ( lhs: Trivia , rhs: Trivia ) -> Trivia {
78+ return lhs. appending ( rhs)
5779 }
5880
5981 /// Concatenates two collections of `Trivia` into the left-hand side.
60- public static func += ( lhs: inout Trivia , rhs: Trivia ) {
61- lhs = lhs + rhs
82+ public static func += ( lhs: inout Trivia , rhs: Trivia ) {
83+ lhs = lhs. appending ( rhs)
6284 }
6385}
6486
@@ -118,13 +140,45 @@ extension Trivia: CustomDebugStringConvertible {
118140 }
119141}
120142
143+ extension Trivia {
144+ /// Decomposes the trivia into pieces that all have count 1
145+ @_spi ( RawSyntax)
146+ public var decomposed : Trivia {
147+ let pieces = self . flatMap ( { ( piece: TriviaPiece ) -> [ TriviaPiece ] in
148+ switch piece {
149+ case . spaces( let count) :
150+ return Array ( repeating: TriviaPiece . spaces ( 1 ) , count: count)
151+ case . tabs( let count) :
152+ return Array ( repeating: TriviaPiece . tabs ( 1 ) , count: count)
153+ case . verticalTabs( let count) :
154+ return Array ( repeating: TriviaPiece . verticalTabs ( 1 ) , count: count)
155+ case . formfeeds( let count) :
156+ return Array ( repeating: TriviaPiece . formfeeds ( 1 ) , count: count)
157+ case . newlines( let count) :
158+ return Array ( repeating: TriviaPiece . newlines ( 1 ) , count: count)
159+ case . backslashes( let count) :
160+ return Array ( repeating: TriviaPiece . backslashes ( 1 ) , count: count)
161+ case . pounds( let count) :
162+ return Array ( repeating: TriviaPiece . pounds ( 1 ) , count: count)
163+ case . carriageReturns( let count) :
164+ return Array ( repeating: TriviaPiece . carriageReturns ( 1 ) , count: count)
165+ case . carriageReturnLineFeeds( let count) :
166+ return Array ( repeating: TriviaPiece . carriageReturnLineFeeds ( 1 ) , count: count)
167+ case . lineComment, . blockComment, . docLineComment, . docBlockComment, . unexpectedText, . shebang:
168+ return [ piece]
169+ }
170+ } )
171+ return Trivia ( pieces: pieces)
172+ }
173+ }
174+
121175extension TriviaPiece {
122176 /// Returns true if the trivia is `.newlines`, `.carriageReturns` or `.carriageReturnLineFeeds`
123177 public var isNewline : Bool {
124178 switch self {
125179 case . newlines,
126- . carriageReturns,
127- . carriageReturnLineFeeds:
180+ . carriageReturns,
181+ . carriageReturnLineFeeds:
128182 return true
129183 default :
130184 return false
@@ -137,8 +191,8 @@ extension RawTriviaPiece {
137191 public var isNewline : Bool {
138192 switch self {
139193 case . newlines,
140- . carriageReturns,
141- . carriageReturnLineFeeds:
194+ . carriageReturns,
195+ . carriageReturnLineFeeds:
142196 return true
143197 default :
144198 return false
0 commit comments