0001    //
0002    //  String+SourceKitten.swift
0003    //  SourceKitten
0004    //
0005    //  Created by JP Simard on 2015-01-05.
0006    //  Copyright (c) 2015 SourceKitten. All rights reserved.
0007    //
0008    
0009    import Foundation
0010    
0011    /// Representation of line in String
0012    public struct Line
File.swift:22
    public var lines: [Line]
String+SourceKitten.swift:45
        let lines: [Line]
String+SourceKitten.swift:73
            var lines = [Line]()
String+SourceKitten.swift:89
                let line = Line(index: lineIndex,
String+SourceKitten.swift:360
    public func lines() -> [Line] {
{ 0013 /// origin = 0 0014 public let index
String+SourceKitten.swift:164
                return (line: line.index, character: offset - line.range.location + 1)
String+SourceKitten.swift:183
                return (line: line.index, character: character)
: Int 0015 /// Content 0016 public let content
String+SourceKitten.swift:126
            let endUTF16index = line.content.utf8.startIndex.advancedBy(diff)
String+SourceKitten.swift:127
                                       .samePositionIn(line.content.utf16)!
String+SourceKitten.swift:128
            let utf16Diff = line.content.utf16.startIndex.distanceTo(endUTF16index)
String+SourceKitten.swift:154
            let endUTF8index = line.content.utf16.startIndex.advancedBy(diff)
String+SourceKitten.swift:155
                                      .samePositionIn(line.content.utf8)!
String+SourceKitten.swift:156
            let byteDiff = line.content.utf8.startIndex.distanceTo(endUTF8index)
String+SourceKitten.swift:174
                let content = line.content
: String 0017 /// UTF16 based range in entire String. Equivalent to Range<UTF16Index> 0018 public let range
String+SourceKitten.swift:122
                return line.range.location
String+SourceKitten.swift:124
                return NSMaxRange(line.range)
String+SourceKitten.swift:129
            return line.range.location + utf16Diff
String+SourceKitten.swift:143
            let index = lines.indexOf({ NSLocationInRange(location, $0.range) })
String+SourceKitten.swift:148
            let diff = location - line.range.location
String+SourceKitten.swift:151
            } else if line.range.length == diff {
String+SourceKitten.swift:161
            let index = lines.indexOf { NSLocationInRange(offset, $0.range) }
String+SourceKitten.swift:164
                return (line: line.index, character: offset - line.range.location + 1)
: NSRange 0019 /// Byte based range in entire String. Equivalent to Range<UTF8Index> 0020 public let byteRange
String+SourceKitten.swift:115
            let index = lines.indexOf({ NSLocationInRange(byteOffset, $0.byteRange) })
String+SourceKitten.swift:120
            let diff = byteOffset - line.byteRange.location
String+SourceKitten.swift:123
            } else if line.byteRange.length == diff {
String+SourceKitten.swift:150
                return line.byteRange.location
String+SourceKitten.swift:152
                return NSMaxRange(line.byteRange)
String+SourceKitten.swift:157
            return line.byteRange.location + byteDiff
String+SourceKitten.swift:169
            let index = lines.indexOf { NSLocationInRange(offset, $0.byteRange) }
String+SourceKitten.swift:175
                let length = offset - line.byteRange.location + 1
String+SourceKitten.swift:176
                if length == line.byteRange.length {
: NSRange 0021 } 0022 0023 private let whitespaceAndNewlineCharacterSet
String+SourceKitten.swift:491
                    let leadingWhitespaceCountToAdd = nsString.substringWithRange(NSRange(location: lineStart, length: lineEnd - lineStart)).countOfLeadingCharactersInSet(whitespaceAndNewlineCharacterSet)
String+SourceKitten.swift:504
                    .stringByTrimmingTrailingCharactersInSet(whitespaceAndNewlineCharacterSet)
String+SourceKitten.swift:516
            let lineLeadingWhitespace = line.countOfLeadingCharactersInSet(whitespaceAndNewlineCharacterSet)
String+SourceKitten.swift:553
        let unwantedSet = whitespaceAndNewlineCharacterSet.mutableCopy() as! NSMutableCharacterSet
= NSCharacterSet.whitespaceAndNewlineCharacterSet() 0024 0025 private let commentLinePrefixCharacterSet
String+SourceKitten.swift:517
            let lineLeadingCharacters = line.countOfLeadingCharactersInSet(commentLinePrefixCharacterSet)
: NSCharacterSet = { 0026 let characterSet = NSMutableCharacterSet.whitespaceAndNewlineCharacterSet() 0027 /** 0028 * For "wall of asterisk" comment blocks, such as this one. 0029 */ 0030 characterSet.addCharactersInString("*") 0031 return characterSet 0032 }() 0033 0034 private var keyCacheContainer
String+SourceKitten.swift:192
        if let cache = objc_getAssociatedObject(self, &keyCacheContainer) as? CacheContainer {
String+SourceKitten.swift:196
        objc_setAssociatedObject(self, &keyCacheContainer, cache, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
= 0 0035 0036 extension NSString { 0037 /** 0038 CacheContainer caches: 0039 0040 - UTF16-based NSRange 0041 - UTF8-based NSRange 0042 - Line 0043 */ 0044 @objc private class CacheContainer
String+SourceKitten.swift:192
        if let cache = objc_getAssociatedObject(self, &keyCacheContainer) as? CacheContainer {
String+SourceKitten.swift:195
        let cache = CacheContainer(self)
String+SourceKitten.swift:191
    private var cacheContainer: CacheContainer {
: NSObject { 0045 let lines
String+SourceKitten.swift:101
            self.lines = lines
String+SourceKitten.swift:112
            if lines.isEmpty {
String+SourceKitten.swift:115
            let index = lines.indexOf({ NSLocationInRange(byteOffset, $0.byteRange) })
String+SourceKitten.swift:117
            guard let line = (index.map { lines[$0] } ?? lines.last) else {
String+SourceKitten.swift:117
            guard let line = (index.map { lines[$0] } ?? lines.last) else {
String+SourceKitten.swift:140
            if lines.isEmpty {
String+SourceKitten.swift:143
            let index = lines.indexOf({ NSLocationInRange(location, $0.range) })
String+SourceKitten.swift:145
            guard let line = (index.map { lines[$0] } ?? lines.last) else {
String+SourceKitten.swift:145
            guard let line = (index.map { lines[$0] } ?? lines.last) else {
String+SourceKitten.swift:161
            let index = lines.indexOf { NSLocationInRange(offset, $0.range) }
String+SourceKitten.swift:163
                let line = lines[$0]
String+SourceKitten.swift:169
            let index = lines.indexOf { NSLocationInRange(offset, $0.byteRange) }
String+SourceKitten.swift:171
                let line = lines[$0]
String+SourceKitten.swift:361
        return cacheContainer.lines
: [Line] 0046 let utf8View
String+SourceKitten.swift:62
            utf8View = string.utf8
String+SourceKitten.swift:84
                let utf8indexEnd = utf16indexEnd.samePositionIn(utf8View)!
: String.UTF8View 0047 0048 init
String+SourceKitten.swift:195
        let cache = CacheContainer(self)
(_ string: NSString) { 0049 // Make a copy of the string to avoid holding a circular reference, which would leak 0050 // memory. 0051 // 0052 // If the string is a `Swift.String`, strongly referencing that in `CacheContainer` does 0053 // not cause a circular reference, because casting `String` to `NSString` makes a new 0054 // `NSString` instance. 0055 // 0056 // If the string is a native `NSString` instance, a circular reference is created when 0057 // assigning `self.utf8View = (string as String).utf8`. 0058 // 0059 // A reference to `NSString` is held by every cast `String` along with their views and 0060 // indices. 0061 let string = string.mutableCopy() as! String 0062 utf8View = string.utf8 0063 0064 var start = 0 // line start 0065 var end = 0 // line end 0066 var contentsEnd = 0 // line end without line delimiter 0067 var lineIndex = 1 // start by 1 0068 var byteOffsetStart = 0 0069 var utf8indexStart = string.utf8.startIndex 0070 var utf16indexStart = string.utf16.startIndex 0071 0072 let nsstring = string as NSString 0073 var lines = [Line]() 0074 while start < nsstring.length { 0075 let range = NSRange(location: start, length: 0) 0076 nsstring.getLineStart(&start, end: &end, contentsEnd: &contentsEnd, forRange: range) 0077 0078 // range 0079 let lineRange = NSRange(location: start, length: end - start) 0080 let contentsRange = NSRange(location: start, length: contentsEnd - start) 0081 0082 // byteRange 0083 let utf16indexEnd = utf16indexStart.advancedBy(end - start) 0084 let utf8indexEnd = utf16indexEnd.samePositionIn(utf8View)! 0085 let byteLength = utf8indexStart.distanceTo(utf8indexEnd) 0086 let byteRange = NSRange(location: byteOffsetStart, length: byteLength) 0087 0088 // line 0089 let line = Line(index: lineIndex, 0090 content: nsstring.substringWithRange(contentsRange), 0091 range: lineRange, byteRange: byteRange) 0092 0093 lines.append(line) 0094 0095 lineIndex += 1 0096 start = end 0097 utf16indexStart = utf16indexEnd 0098 utf8indexStart = utf8indexEnd 0099 byteOffsetStart += byteLength 0100 } 0101 self.lines = lines 0102 } 0103 0104 /** 0105 Returns UTF16 offset from UTF8 offset. 0106 0107 - parameter byteOffset: UTF8-based offset of string. 0108 0109 - returns: UTF16 based offset of string. 0110 */ 0111 func locationFromByteOffset
String+SourceKitten.swift:261
        let utf16Start = cacheContainer.locationFromByteOffset(start)
String+SourceKitten.swift:265
        let utf16End = cacheContainer.locationFromByteOffset(start + length)
(byteOffset: Int) -> Int { 0112 if lines.isEmpty { 0113 return 0 0114 } 0115 let index = lines.indexOf({ NSLocationInRange(byteOffset, $0.byteRange) }) 0116 // byteOffset may be out of bounds when sourcekitd points end of string. 0117 guard let line = (index.map { lines[$0] } ?? lines.last) else { 0118 fatalError() 0119 } 0120 let diff = byteOffset - line.byteRange.location 0121 if diff == 0 { 0122 return line.range.location 0123 } else if line.byteRange.length == diff { 0124 return NSMaxRange(line.range) 0125 } 0126 let endUTF16index = line.content.utf8.startIndex.advancedBy(diff) 0127 .samePositionIn(line.content.utf16)! 0128 let utf16Diff = line.content.utf16.startIndex.distanceTo(endUTF16index) 0129 return line.range.location + utf16Diff 0130 } 0131 0132 /** 0133 Returns UTF8 offset from UTF16 offset. 0134 0135 - parameter location: UTF16-based offset of string. 0136 0137 - returns: UTF8 based offset of string. 0138 */ 0139 func byteOffsetFromLocation
String+SourceKitten.swift:298
            byteOffset = cacheContainer.byteOffsetFromLocation(start)
(location: Int) -> Int { 0140 if lines.isEmpty { 0141 return 0 0142 } 0143 let index = lines.indexOf({ NSLocationInRange(location, $0.range) }) 0144 // location may be out of bounds when NSRegularExpression points end of string. 0145 guard let line = (index.map { lines[$0] } ?? lines.last) else { 0146 fatalError() 0147 } 0148 let diff = location - line.range.location 0149 if diff == 0 { 0150 return line.byteRange.location 0151 } else if line.range.length == diff { 0152 return NSMaxRange(line.byteRange) 0153 } 0154 let endUTF8index = line.content.utf16.startIndex.advancedBy(diff) 0155 .samePositionIn(line.content.utf8)! 0156 let byteDiff = line.content.utf8.startIndex.distanceTo(endUTF8index) 0157 return line.byteRange.location + byteDiff 0158 } 0159 0160 func lineAndCharacterForCharacterOffset
String+SourceKitten.swift:206
        return cacheContainer.lineAndCharacterForCharacterOffset(offset)
(offset: Int) -> (line: Int, character: Int)? { 0161 let index = lines.indexOf { NSLocationInRange(offset, $0.range) } 0162 return index.map { 0163 let line = lines[$0] 0164 return (line: line.index, character: offset - line.range.location + 1) 0165 } 0166 } 0167 0168 func lineAndCharacterForByteOffset
String+SourceKitten.swift:215
        return cacheContainer.lineAndCharacterForByteOffset(offset)
(offset: Int) -> (line: Int, character: Int)? { 0169 let index = lines.indexOf { NSLocationInRange(offset, $0.byteRange) } 0170 return index.map { 0171 let line = lines[$0] 0172 0173 let character: Int 0174 let content = line.content 0175 let length = offset - line.byteRange.location + 1 0176 if length == line.byteRange.length { 0177 character = content.utf16.count 0178 } else { 0179 let endIndex = content.utf8.startIndex.advancedBy(length) 0180 .samePositionIn(content.utf16) ?? content.utf16.endIndex 0181 character = content.utf16.startIndex.distanceTo(endIndex) 0182 } 0183 return (line: line.index, character: character) 0184 } 0185 } 0186 } 0187 0188 /** 0189 CacheContainer instance is stored to instance of NSString as associated object. 0190 */ 0191 private var cacheContainer
String+SourceKitten.swift:206
        return cacheContainer.lineAndCharacterForCharacterOffset(offset)
String+SourceKitten.swift:215
        return cacheContainer.lineAndCharacterForByteOffset(offset)
String+SourceKitten.swift:261
        let utf16Start = cacheContainer.locationFromByteOffset(start)
String+SourceKitten.swift:265
        let utf16End = cacheContainer.locationFromByteOffset(start + length)
String+SourceKitten.swift:298
            byteOffset = cacheContainer.byteOffsetFromLocation(start)
String+SourceKitten.swift:361
        return cacheContainer.lines
: CacheContainer { 0192 if let cache = objc_getAssociatedObject(self, &keyCacheContainer) as? CacheContainer { 0193 return cache 0194 } 0195 let cache = CacheContainer(self) 0196 objc_setAssociatedObject(self, &keyCacheContainer, cache, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 0197 return cache 0198 } 0199 0200 /** 0201 Returns line number and character for utf16 based offset. 0202 0203 - parameter offset: utf16 based index. 0204 */ 0205 public func lineAndCharacterForCharacterOffset(offset: Int) -> (line: Int, character: Int)? { 0206 return cacheContainer.lineAndCharacterForCharacterOffset(offset) 0207 } 0208 0209 /** 0210 Returns line number and character for byte offset. 0211 0212 - parameter offset: byte offset. 0213 */ 0214 public func lineAndCharacterForByteOffset
File.swift:321
                let commentEndLine = (contents as NSString).lineAndCharacterForByteOffset(commentByteRange.endIndex)?.line
File.swift:322
                let tokenStartLine = (contents as NSString).lineAndCharacterForByteOffset(Int(offset))?.line
(offset: Int) -> (line: Int, character: Int)? { 0215 return cacheContainer.lineAndCharacterForByteOffset(offset) 0216 } 0217 0218 /** 0219 Returns a copy of `self` with the trailing contiguous characters belonging to `characterSet` 0220 removed. 0221 0222 - parameter characterSet: Character set to check for membership. 0223 */ 0224 public func stringByTrimmingTrailingCharactersInSet
String+SourceKitten.swift:504
                    .stringByTrimmingTrailingCharactersInSet(whitespaceAndNewlineCharacterSet)
(characterSet: NSCharacterSet) -> String { 0225 if length == 0 { 0226 return self as String 0227 } 0228 var charBuffer = [unichar](count: length, repeatedValue: 0) 0229 getCharacters(&charBuffer) 0230 for newLength in (1...length).reverse() { 0231 if !characterSet.characterIsMember(charBuffer[newLength - 1]) { 0232 return substringWithRange(NSRange(location: 0, length: newLength)) 0233 } 0234 } 0235 return "" 0236 } 0237 0238 /** 0239 Returns self represented as an absolute path. 0240 0241 - parameter rootDirectory: Absolute parent path if not already an absolute path. 0242 */ 0243 public func absolutePathRepresentation
File.swift:30
        self.path = (path as NSString).absolutePathRepresentation()
Xcode.swift:164
        headerFiles.append(xcodebuildArguments.removeAtIndex(0).absolutePathRepresentation())
(rootDirectory: String = NSFileManager.defaultManager().currentDirectoryPath) -> String { 0244 if absolutePath { 0245 return self as String 0246 } 0247 return (NSString.pathWithComponents([rootDirectory, self as String]) as NSString).stringByStandardizingPath 0248 } 0249 0250 /** 0251 Converts a range of byte offsets in `self` to an `NSRange` suitable for filtering `self` as an 0252 `NSString`. 0253 0254 - parameter start: Starting byte offset. 0255 - parameter length: Length of bytes to include in range. 0256 0257 - returns: An equivalent `NSRange`. 0258 */ 0259 public func byteRangeToNSRange
File.swift:326
                return contents.byteRangeToNSRange(start: commentByteRange.startIndex, length: commentByteRange.endIndex - commentByteRange.startIndex).flatMap { nsRange in
SourceDeclaration.swift:20
        file.contents.byteRangeToNSRange(start: $0.range.location, length: $0.range.length) ?? NSRange()
SourceDeclaration.swift:24
        let range = file.contents.byteRangeToNSRange(start: declaration.range.location, length: declaration.range.length)
String+SourceKitten.swift:316
        return byteRangeToNSRange(start: start, length: length).map(substringWithRange)
String+SourceKitten.swift:327
        return byteRangeToNSRange(start: start, length: length).map { range in
String+SourceKitten.swift:341
        return byteRangeToNSRange(start: start, length: length).flatMap { range in
(start start: Int, length: Int) -> NSRange? { 0260 if self.length == 0 { return nil } 0261 let utf16Start = cacheContainer.locationFromByteOffset(start) 0262 if length == 0 { 0263 return NSRange(location: utf16Start, length: 0) 0264 } 0265 let utf16End = cacheContainer.locationFromByteOffset(start + length) 0266 return NSRange(location: utf16Start, length: utf16End - utf16Start) 0267 } 0268 0269 /** 0270 Converts an `NSRange` suitable for filtering `self` as an 0271 `NSString` to a range of byte offsets in `self`. 0272 0273 - parameter start: Starting character index in the string. 0274 - parameter length: Number of characters to include in range. 0275 0276 - returns: An equivalent `NSRange`. 0277 */ 0278 public func NSRangeToByteRange
String+SourceKitten.swift:411
            guard let markByteRange = self.NSRangeToByteRange(start: markRange.location, length: markRange.length) else {
(start start: Int, length: Int) -> NSRange? { 0279 let string = self as String 0280 0281 let utf16View = string.utf16 0282 let startUTF16Index = utf16View.startIndex.advancedBy(start) 0283 let endUTF16Index = startUTF16Index.advancedBy(length) 0284 0285 let utf8View = string.utf8 0286 guard let startUTF8Index = startUTF16Index.samePositionIn(utf8View), 0287 let endUTF8Index = endUTF16Index.samePositionIn(utf8View) else { 0288 return nil 0289 } 0290 0291 // Don't using `CacheContainer` if string is short. 0292 // There are two reasons for: 0293 // 1. Avoid using associatedObject on NSTaggedPointerString (< 7 bytes) because that does 0294 // not free associatedObject. 0295 // 2. Using cache is overkill for short string. 0296 let byteOffset: Int 0297 if utf16View.count > 50 { 0298 byteOffset = cacheContainer.byteOffsetFromLocation(start) 0299 } else { 0300 byteOffset = utf8View.startIndex.distanceTo(startUTF8Index) 0301 } 0302 0303 // `cacheContainer` will hit for below, but that will be calculated from startUTF8Index 0304 // in most case. 0305 let length = startUTF8Index.distanceTo(endUTF8Index) 0306 return NSRange(location: byteOffset, length: length) 0307 } 0308 0309 /** 0310 Returns a substring with the provided byte range. 0311 0312 - parameter start: Starting byte offset. 0313 - parameter length: Length of bytes to include in range. 0314 */ 0315 public func substringWithByteRange
String+SourceKitten.swift:382
        return substringWithByteRange(start: Int(start.offset), length: Int(end.offset - start.offset))
String+SourceKitten.swift:435
            return ((self as NSString).substringWithByteRange(start: token.offset, length: token.length))
(start start: Int, length: Int) -> String? { 0316 return byteRangeToNSRange(start: start, length: length).map(substringWithRange) 0317 } 0318 0319 /** 0320 Returns a substring starting at the beginning of `start`'s line and ending at the end of `end`'s 0321 line. Returns `start`'s entire line if `end` is nil. 0322 0323 - parameter start: Starting byte offset. 0324 - parameter length: Length of bytes to include in range. 0325 */ 0326 public func substringLinesWithByteRange
File.swift:69
            return contents.substringLinesWithByteRange(start: start, length: length)?
(start start: Int, length: Int) -> String? { 0327 return byteRangeToNSRange(start: start, length: length).map { range in 0328 var lineStart = 0, lineEnd = 0 0329 getLineStart(&lineStart, end: &lineEnd, contentsEnd: nil, forRange: range) 0330 return substringWithRange(NSRange(location: lineStart, length: lineEnd - lineStart)) 0331 } 0332 } 0333 0334 /** 0335 Returns line numbers containing starting and ending byte offsets. 0336 0337 - parameter start: Starting byte offset. 0338 - parameter length: Length of bytes to include in range. 0339 */ 0340 public func lineRangeWithByteRange
File.swift:93
            return contents.lineRangeWithByteRange(start: start, length: length)
String+SourceKitten.swift:415
                line: UInt32((self as NSString).lineRangeWithByteRange(start: markByteRange.location, length: 0)!.start),
(start start: Int, length: Int) -> (start: Int, end: Int)? { 0341 return byteRangeToNSRange(start: start, length: length).flatMap { range in 0342 var numberOfLines = 0, index = 0, lineRangeStart = 0 0343 while index < self.length { 0344 numberOfLines += 1 0345 if index <= range.location { 0346 lineRangeStart = numberOfLines 0347 } 0348 index = NSMaxRange(lineRangeForRange(NSRange(location: index, length: 1))) 0349 if index > NSMaxRange(range) { 0350 return (lineRangeStart, numberOfLines) 0351 } 0352 } 0353 return nil 0354 } 0355 } 0356 0357 /** 0358 Returns an array of Lines for each line in the file. 0359 */ 0360 public func lines
File.swift:33
            lines = contents.lines()
File.swift:51
        lines = contents.lines()
() -> [Line] { 0361 return cacheContainer.lines 0362 } 0363 0364 /** 0365 Returns true if self is an Objective-C header file. 0366 */ 0367 public func isObjectiveCHeaderFile
Xcode.swift:163
    while let headerFile = xcodebuildArguments.first where headerFile.isObjectiveCHeaderFile() {
() -> Bool { 0368 return ["h", "hpp", "hh"].contains(pathExtension) 0369 } 0370 0371 /** 0372 Returns true if self is a Swift file. 0373 */ 0374 public func isSwiftFile
Module.swift:70
        sourceFiles = compilerArguments.filter({ $0.isSwiftFile() }).map { ($0 as NSString).stringByResolvingSymlinksInPath }
() -> Bool { 0375 return pathExtension == "swift" 0376 } 0377 0378 /** 0379 Returns a substring from a start and end SourceLocation. 0380 */ 0381 public func substringWithSourceRange
Clang+SourceKitten.swift:84
        return contents.substringWithSourceRange(cursorExtent.start, end: cursorExtent.end)
(start: SourceLocation, end: SourceLocation) -> String? { 0382 return substringWithByteRange(start: Int(start.offset), length: Int(end.offset - start.offset)) 0383 } 0384 } 0385 0386 extension String { 0387 /// Returns the `#pragma mark`s in the string. 0388 /// Just the content; no leading dashes or leading `#pragma mark`. 0389 public func pragmaMarks
SourceDeclaration.swift:19
    let currentMarks = file.contents.pragmaMarks(path, excludeRanges: declarations.map({
(filename: String, excludeRanges: [NSRange], limitRange: NSRange?) -> [SourceDeclaration] { 0390 let regex = try! NSRegularExpression(pattern: "(#pragma\\smark|@name)[ -]*([^\\n]+)", options: []) // Safe to force try 0391 let range: NSRange 0392 if let limitRange = limitRange { 0393 range = NSRange(location: limitRange.location, length: min(utf16.count - limitRange.location, limitRange.length)) 0394 } else { 0395 range = NSRange(location: 0, length: utf16.count) 0396 } 0397 let matches = regex.matchesInString(self, options: [], range: range) 0398 0399 return matches.flatMap { match in 0400 let markRange = match.rangeAtIndex(2) 0401 for excludedRange in excludeRanges { 0402 if NSIntersectionRange(excludedRange, markRange).length > 0 { 0403 return nil 0404 } 0405 } 0406 let markString = (self as NSString).substringWithRange(markRange) 0407 .stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) 0408 if markString.isEmpty { 0409 return nil 0410 } 0411 guard let markByteRange = self.NSRangeToByteRange(start: markRange.location, length: markRange.length) else { 0412 return nil 0413 } 0414 let location = SourceLocation(file: filename, 0415 line: UInt32((self as NSString).lineRangeWithByteRange(start: markByteRange.location, length: 0)!.start), 0416 column: 1, offset: UInt32(markByteRange.location)) 0417 return SourceDeclaration(type: .Mark, location: location, extent: (location, location), name: markString, 0418 usr: nil, declaration: nil, documentation: nil, commentBody: nil, children: []) 0419 } 0420 } 0421 0422 /** 0423 Returns whether or not the `token` can be documented. Either because it is a 0424 `SyntaxKind.Identifier` or because it is a function treated as a `SyntaxKind.Keyword`: 0425 0426 - `subscript` 0427 - `init` 0428 - `deinit` 0429 0430 - parameter token: Token to process. 0431 */ 0432 public func isTokenDocumentable
String+SourceKitten.swift:449
        let documentableOffsets = syntaxMap.tokens.filter(isTokenDocumentable).map {
(token: SyntaxToken) -> Bool { 0433 if token.type == SyntaxKind.Keyword.rawValue { 0434 let keywordFunctions = ["subscript", "init", "deinit"] 0435 return ((self as NSString).substringWithByteRange(start: token.offset, length: token.length)) 0436 .map(keywordFunctions.contains) ?? false 0437 } 0438 return token.type == SyntaxKind.Identifier.rawValue 0439 } 0440 0441 /** 0442 Find integer offsets of documented Swift tokens in self. 0443 0444 - parameter syntaxMap: Syntax Map returned from SourceKit editor.open request. 0445 0446 - returns: Array of documented token offsets. 0447 */ 0448 public func documentedTokenOffsets
SwiftDocs.swift:57
            let documentedTokenOffsets = file.contents.documentedTokenOffsets(syntaxMap)
(syntaxMap: SyntaxMap) -> [Int] { 0449 let documentableOffsets = syntaxMap.tokens.filter(isTokenDocumentable).map { 0450 $0.offset 0451 } 0452 0453 let regex = try! NSRegularExpression(pattern: "(///.*\\n|\\*/\\n)", options: []) // Safe to force try 0454 let range = NSRange(location: 0, length: utf16.count) 0455 let matches = regex.matchesInString(self, options: [], range: range) 0456 0457 return matches.flatMap { match in 0458 documentableOffsets.filter({ $0 >= match.range.location }).first 0459 } 0460 } 0461 0462 /** 0463 Returns the body of the comment if the string is a comment. 0464 0465 - parameter range: Range to restrict the search for a comment body. 0466 */ 0467 public func commentBody
Clang+SourceKitten.swift:149
        var commentBody = rawComment?.commentBody()
File.swift:327
                    return contents.commentBody(nsRange)
(range: NSRange? = nil) -> String? { 0468 let nsString = self as NSString 0469 let patterns: [(pattern: String, options: NSRegularExpressionOptions)] = [ 0470 ("^\\s*\\/\\*\\*\\s*(.*?)\\*\\/", [.AnchorsMatchLines, .DotMatchesLineSeparators]), // multi: ^\s*\/\*\*\s*(.*?)\*\/ 0471 ("^\\s*\\/\\/\\/(.+)?", .AnchorsMatchLines) // single: ^\s*\/\/\/(.+)? 0472 ] 0473 let range = range ?? NSRange(location: 0, length: nsString.length) 0474 for pattern in patterns { 0475 let regex = try! NSRegularExpression(pattern: pattern.pattern, options: pattern.options) // Safe to force try 0476 let matches = regex.matchesInString(self, options: [], range: range) 0477 let bodyParts = matches.flatMap { match -> [String] in 0478 let numberOfRanges = match.numberOfRanges 0479 if numberOfRanges < 1 { 0480 return [] 0481 } 0482 return (1..<numberOfRanges).map { rangeIndex in 0483 let range = match.rangeAtIndex(rangeIndex) 0484 if range.location == NSNotFound { 0485 return "" // empty capture group, return empty string 0486 } 0487 var lineStart = 0 0488 var lineEnd = nsString.length 0489 let indexRange = NSRange(location: range.location, length: 0) 0490 nsString.getLineStart(&lineStart, end: &lineEnd, contentsEnd: nil, forRange: indexRange) 0491 let leadingWhitespaceCountToAdd = nsString.substringWithRange(NSRange(location: lineStart, length: lineEnd - lineStart)).countOfLeadingCharactersInSet(whitespaceAndNewlineCharacterSet) 0492 let leadingWhitespaceToAdd = String(count: leadingWhitespaceCountToAdd, repeatedValue: Character(" ")) 0493 0494 let bodySubstring = nsString.substringWithRange(range) 0495 if bodySubstring.containsString("@name") { 0496 return "" // appledoc directive, return empty string 0497 } 0498 return leadingWhitespaceToAdd + bodySubstring 0499 } 0500 } 0501 if bodyParts.count > 0 { 0502 return bodyParts 0503 .joinWithSeparator("\n") 0504 .stringByTrimmingTrailingCharactersInSet(whitespaceAndNewlineCharacterSet) 0505 .stringByRemovingCommonLeadingWhitespaceFromLines() 0506 } 0507 } 0508 return nil 0509 } 0510 0511 /// Returns a copy of `self` with the leading whitespace common in each line removed. 0512 public func stringByRemovingCommonLeadingWhitespaceFromLines
Clang+SourceKitten.swift:202
        return [.Para(ret.stringByRemovingCommonLeadingWhitespaceFromLines(), kindString)]
String+SourceKitten.swift:505
                    .stringByRemovingCommonLeadingWhitespaceFromLines()
() -> String { 0513 var minLeadingCharacters = Int.max 0514 0515 enumerateLines { line, _ in 0516 let lineLeadingWhitespace = line.countOfLeadingCharactersInSet(whitespaceAndNewlineCharacterSet) 0517 let lineLeadingCharacters = line.countOfLeadingCharactersInSet(commentLinePrefixCharacterSet) 0518 // Is this prefix smaller than our last and not entirely whitespace? 0519 if lineLeadingCharacters < minLeadingCharacters && lineLeadingWhitespace != line.characters.count { 0520 minLeadingCharacters = lineLeadingCharacters 0521 } 0522 } 0523 var lines = [String]() 0524 enumerateLines { line, _ in 0525 if line.characters.count >= minLeadingCharacters { 0526 lines.append(line[line.startIndex.advancedBy(minLeadingCharacters)..<line.endIndex]) 0527 } else { 0528 lines.append(line) 0529 } 0530 } 0531 return lines.joinWithSeparator("\n") 0532 } 0533 0534 /** 0535 Returns the number of contiguous characters at the start of `self` belonging to `characterSet`. 0536 0537 - parameter characterSet: Character set to check for membership. 0538 */ 0539 public func countOfLeadingCharactersInSet
String+SourceKitten.swift:491
                    let leadingWhitespaceCountToAdd = nsString.substringWithRange(NSRange(location: lineStart, length: lineEnd - lineStart)).countOfLeadingCharactersInSet(whitespaceAndNewlineCharacterSet)
String+SourceKitten.swift:516
            let lineLeadingWhitespace = line.countOfLeadingCharactersInSet(whitespaceAndNewlineCharacterSet)
String+SourceKitten.swift:517
            let lineLeadingCharacters = line.countOfLeadingCharactersInSet(commentLinePrefixCharacterSet)
(characterSet: NSCharacterSet) -> Int { 0540 let utf16View = utf16 0541 var count = 0 0542 for char in utf16View { 0543 if !characterSet.characterIsMember(char) { 0544 break 0545 } 0546 count += 1 0547 } 0548 return count 0549 } 0550 0551 /// Returns a copy of the string by trimming whitespace and the opening curly brace (`{`). 0552 internal func stringByTrimmingWhitespaceAndOpeningCurlyBrace
File.swift:70
                .stringByTrimmingWhitespaceAndOpeningCurlyBrace()
() -> String? { 0553 let unwantedSet = whitespaceAndNewlineCharacterSet.mutableCopy() as! NSMutableCharacterSet 0554 unwantedSet.addCharactersInString("{") 0555 return stringByTrimmingCharactersInSet(unwantedSet) 0556 } 0557 } 0558