1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Foundation
import SwiftSyntax
extension StringProtocol {
/// Trims whitespace from the end of a string, returning a new string with no trailing whitespace.
///
/// If the string is only whitespace, an empty string is returned.
///
/// - Returns: The string with trailing whitespace removed.
func trimmingTrailingWhitespace() -> String {
if isEmpty { return String() }
let scalars = unicodeScalars
var idx = scalars.index(before: scalars.endIndex)
while scalars[idx].properties.isWhitespace {
if idx == scalars.startIndex { return String() }
idx = scalars.index(before: idx)
}
return String(String.UnicodeScalarView(scalars[...idx]))
}
}
struct Comment {
enum Kind {
case line, docLine, block, docBlock
/// The length of the characters starting the comment.
var prefixLength: Int {
switch self {
// `//`, `/*`
case .line, .block: return 2
// `///`, `/**`
case .docLine, .docBlock: return 3
}
}
var prefix: String {
switch self {
case .line: return "//"
case .block: return "/*"
case .docBlock: return "/**"
case .docLine: return "///"
}
}
}
let kind: Kind
var text: [String]
var length: Int
init(kind: Kind, text: String) {
self.kind = kind
switch kind {
case .line, .docLine:
self.text = [text]
self.text[0].removeFirst(kind.prefixLength)
self.length = self.text.reduce(0, { $0 + $1.count + kind.prefixLength + 1 })
case .block, .docBlock:
var fulltext: String = text
fulltext.removeFirst(kind.prefixLength)
fulltext.removeLast(2)
let lines = fulltext.split(separator: "\n", omittingEmptySubsequences: false)
// The last line in a block style comment contains the "*/" pattern to end the comment. The
// trailing space(s) need to be kept in that line to have space between text and "*/".
var trimmedLines = lines.dropLast().map({ $0.trimmingTrailingWhitespace() })
if let lastLine = lines.last {
trimmedLines.append(String(lastLine))
}
self.text = trimmedLines
self.length = self.text.reduce(0, { $0 + $1.count }) + kind.prefixLength + 3
}
}
func print(indent: [Indent]) -> String {
switch self.kind {
case .line, .docLine:
let separator = "\n" + indent.indentation() + kind.prefix
let trimmedLines = self.text.map { $0.trimmingTrailingWhitespace() }
return kind.prefix + trimmedLines.joined(separator: separator)
case .block, .docBlock:
let separator = "\n"
return kind.prefix + self.text.joined(separator: separator) + "*/"
}
}
mutating func addText(_ text: [String]) {
for line in text {
self.text.append(line)
self.length += line.count + self.kind.prefixLength + 1
}
}
}
|