@@ -16,56 +16,48 @@ import LSPLogging
16
16
17
17
/// A ranged token in the document used for syntax highlighting.
18
18
public struct SyntaxHighlightingToken : Hashable {
19
- public var start : Position
20
- public var length : Int
19
+ /// The range of the token in the document. Must be on a single line.
20
+ public var range : Range < Position > {
21
+ didSet {
22
+ assert ( range. lowerBound. line == range. upperBound. line)
23
+ }
24
+ }
25
+ /// The token type.
21
26
public var kind : Kind
27
+ /// Additional metadata about the token.
22
28
public var modifiers : Modifiers
23
29
24
- /// The end of a token. Note that this requires the token to be
25
- /// on a single line, which is the case for all tokens emitted
26
- /// by parseTokens, however.
27
- public var sameLineEnd : Position {
28
- Position ( line: start. line, utf16index: start. utf16index + length)
30
+ /// The (inclusive) start position of the token.
31
+ /// Setting it shifts the token and preserves the length.
32
+ public var start : Position {
33
+ get { range. lowerBound }
34
+ set {
35
+ let length = utf16length
36
+ range = newValue..< Position ( line: newValue. line, utf16index: newValue. utf16index + length)
37
+ }
29
38
}
30
- public var sameLineRange : Range < Position > {
31
- start..< sameLineEnd
39
+ /// The (exclusive) end position of the token.
40
+ public var end : Position { range. upperBound }
41
+ /// The length of the token in UTF-16 code units.
42
+ public var utf16length : Int {
43
+ get { end. utf16index - start. utf16index }
44
+ set {
45
+ assert ( newValue >= 0 )
46
+ range = start..< Position ( line: start. line, utf16index: start. utf16index + newValue)
47
+ }
32
48
}
33
49
34
- public init (
35
- start: Position ,
36
- length: Int ,
37
- kind: Kind ,
38
- modifiers: Modifiers = [ ]
39
- ) {
40
- self . start = start
41
- self . length = length
50
+ public init ( range: Range < Position > , kind: Kind , modifiers: Modifiers = [ ] ) {
51
+ assert ( range. lowerBound. line == range. upperBound. line)
52
+
53
+ self . range = range
42
54
self . kind = kind
43
55
self . modifiers = modifiers
44
56
}
45
57
46
- /// Splits a potentially multi-line token to multiple single-line tokens.
47
- public func splitToSingleLineTokens( in snapshot: DocumentSnapshot ) -> [ Self ] {
48
- guard let startIndex = snapshot. index ( of: start) else {
49
- fatalError ( " Token \( self ) begins outside of the document " )
50
- }
51
-
52
- let endIndex = snapshot. text. index ( startIndex, offsetBy: length)
53
- let text = snapshot. text [ startIndex..< endIndex]
54
- let lines = text. split ( separator: " \n " )
55
-
56
- return lines
57
- . enumerated ( )
58
- . map { ( i, content) in
59
- Self (
60
- start: Position (
61
- line: start. line + i,
62
- utf16index: i == 0 ? start. utf16index : 0
63
- ) ,
64
- length: content. count,
65
- kind: kind,
66
- modifiers: modifiers
67
- )
68
- }
58
+ public init ( start: Position , utf16length: Int , kind: Kind , modifiers: Modifiers = [ ] ) {
59
+ let range = start..< Position ( line: start. line, utf16index: start. utf16index + utf16length)
60
+ self . init ( range: range, kind: kind, modifiers: modifiers)
69
61
}
70
62
71
63
/// The token type. Represented using an int to make the conversion to
@@ -223,7 +215,7 @@ extension Array where Element == SyntaxHighlightingToken {
223
215
rawTokens += [
224
216
UInt32 ( lineDelta) ,
225
217
UInt32 ( charDelta) ,
226
- UInt32 ( token. length ) ,
218
+ UInt32 ( token. utf16length ) ,
227
219
token. kind. rawValue,
228
220
token. modifiers. rawValue
229
221
]
@@ -236,8 +228,35 @@ extension Array where Element == SyntaxHighlightingToken {
236
228
/// preferring the given array's tokens if duplicate ranges are
237
229
/// found.
238
230
public func mergingTokens( with other: [ SyntaxHighlightingToken ] ) -> [ SyntaxHighlightingToken ] {
239
- let otherRanges = Set ( other. map ( \. sameLineRange) )
240
- return filter { !otherRanges. contains ( $0. sameLineRange) } + other
231
+ let otherRanges = Set ( other. map ( \. range) )
232
+ return filter { !otherRanges. contains ( $0. range) } + other
233
+ }
234
+ }
235
+
236
+ extension Range where Bound == Position {
237
+ /// Splits a potentially multi-line range to multiple single-line ranges.
238
+ fileprivate func splitToSingleLineRanges( in snapshot: DocumentSnapshot ) -> [ Self ] {
239
+ guard let startIndex = snapshot. index ( of: lowerBound) ,
240
+ let endIndex = snapshot. index ( of: upperBound) else {
241
+ fatalError ( " Range \( self ) reaches outside of the document " )
242
+ }
243
+
244
+ let text = snapshot. text [ startIndex..< endIndex]
245
+ let lines = text. split ( separator: " \n " )
246
+
247
+ return lines
248
+ . enumerated ( )
249
+ . map { ( i, content) in
250
+ let start = Position (
251
+ line: lowerBound. line + i,
252
+ utf16index: i == 0 ? lowerBound. utf16index : 0
253
+ )
254
+ let end = Position (
255
+ line: start. line,
256
+ utf16index: start. utf16index + content. utf16. count
257
+ )
258
+ return start..< end
259
+ }
241
260
}
242
261
}
243
262
@@ -271,7 +290,7 @@ struct SyntaxHighlightingTokenParser {
271
290
if useName && [ . function, . method, . enumMember] . contains ( kind) && modifiers. contains ( . declaration) ,
272
291
let name: String = response [ keys. name] ,
273
292
name. contains ( " ( " ) ,
274
- let funcNameLength: Int = name. split ( separator: " ( " ) . first? . utf16 . count {
293
+ let funcNameLength: Int = name. split ( separator: " ( " ) . first? . utf8 . count {
275
294
length = funcNameLength
276
295
}
277
296
@@ -282,14 +301,18 @@ struct SyntaxHighlightingTokenParser {
282
301
length += 2
283
302
}
284
303
285
- let multiLineToken = SyntaxHighlightingToken (
286
- start: start,
287
- length: length,
288
- kind: kind,
289
- modifiers: modifiers
290
- )
291
-
292
- tokens += multiLineToken. splitToSingleLineTokens ( in: snapshot)
304
+ if let end: Position = snapshot. positionOf ( utf8Offset: offset + length) {
305
+ let multiLineRange = start..< end
306
+ let ranges = multiLineRange. splitToSingleLineRanges ( in: snapshot)
307
+
308
+ tokens += ranges. map {
309
+ SyntaxHighlightingToken (
310
+ range: $0,
311
+ kind: kind,
312
+ modifiers: modifiers
313
+ )
314
+ }
315
+ }
293
316
}
294
317
295
318
if let substructure: SKDResponseArray = response [ keys. substructure] {
0 commit comments