HTMLOutputFormat: Merge same-type tokens along with whitespace
This change makes Splash merge tokens of the same type (along with any whitespace in between them) when generating HTML. The result is much smaller HTML, since less tags have to be used to produce the same result. This was most obvious with comment highlighting, for example, this comment: ``` // Hello I’m a comment ``` Would generate 5 different <span class="comment"></span> elements. Now it’s just one!
This commit is contained in:
parent
59161f2724
commit
6dff287cd2
@ -27,26 +27,60 @@ public extension HTMLOutputFormat {
|
||||
struct Builder: OutputBuilder {
|
||||
private let classPrefix: String
|
||||
private var html = ""
|
||||
private var pendingToken: (string: String, type: TokenType)?
|
||||
private var pendingWhitespace: String?
|
||||
|
||||
fileprivate init(classPrefix: String) {
|
||||
self.classPrefix = classPrefix
|
||||
}
|
||||
|
||||
public mutating func addToken(_ token: String, ofType type: TokenType) {
|
||||
html.append("<span class=\"\(classPrefix)\(type.string)\">\(token.escaped)</span>")
|
||||
if var pending = pendingToken {
|
||||
guard pending.type != type else {
|
||||
pendingWhitespace.map { pending.string += $0 }
|
||||
pendingWhitespace = nil
|
||||
pending.string += token
|
||||
pendingToken = pending
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
appendPending()
|
||||
pendingToken = (token, type)
|
||||
}
|
||||
|
||||
public mutating func addPlainText(_ text: String) {
|
||||
appendPending()
|
||||
html.append(text.escaped)
|
||||
}
|
||||
|
||||
public mutating func addWhitespace(_ whitespace: String) {
|
||||
html.append(whitespace)
|
||||
if pendingToken != nil {
|
||||
pendingWhitespace = (pendingWhitespace ?? "") + whitespace
|
||||
} else {
|
||||
html.append(whitespace)
|
||||
}
|
||||
}
|
||||
|
||||
public func build() -> String {
|
||||
public mutating func build() -> String {
|
||||
appendPending()
|
||||
return html
|
||||
}
|
||||
|
||||
private mutating func appendPending() {
|
||||
if let pending = pendingToken {
|
||||
html.append("""
|
||||
<span class="\(classPrefix)\(pending.type.string)">\(pending.string.escaped)</span>
|
||||
""")
|
||||
|
||||
pendingToken = nil
|
||||
}
|
||||
|
||||
if let whitespace = pendingWhitespace {
|
||||
html.append(whitespace)
|
||||
pendingWhitespace = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,5 +21,5 @@ public protocol OutputBuilder {
|
||||
/// Add some whitespace to the builder
|
||||
mutating func addWhitespace(_ whitespace: String)
|
||||
/// Build the final output based on the builder's current state
|
||||
func build() -> Output
|
||||
mutating func build() -> Output
|
||||
}
|
||||
|
@ -10,6 +10,20 @@ final class HTMLOutputFormatTests: SplashTestCase {
|
||||
highlighter = SyntaxHighlighter(format: HTMLOutputFormat())
|
||||
}
|
||||
|
||||
func testBasicGeneration() {
|
||||
let html = highlighter.highlight("""
|
||||
public struct Test: SomeProtocol {
|
||||
func hello() -> Int { return 7 }
|
||||
}
|
||||
""")
|
||||
|
||||
XCTAssertEqual(html, """
|
||||
<span class="keyword">public struct</span> Test: <span class="type">SomeProtocol</span> {
|
||||
<span class="keyword">func</span> hello() -> <span class="type">Int</span> { <span class="keyword">return</span> <span class="number">7</span> }
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
func testStrippingGreaterAndLessThanCharactersFromOutput() {
|
||||
let html = highlighter.highlight("Array<String>")
|
||||
|
||||
@ -18,6 +32,14 @@ final class HTMLOutputFormatTests: SplashTestCase {
|
||||
""")
|
||||
}
|
||||
|
||||
func testCommentMerging() {
|
||||
let html = highlighter.highlight("// Hey I'm a comment!")
|
||||
|
||||
XCTAssertEqual(html, """
|
||||
<span class="comment">// Hey I'm a comment!</span>
|
||||
""")
|
||||
}
|
||||
|
||||
func testAllTestsRunOnLinux() {
|
||||
XCTAssertTrue(TestCaseVerifier.verifyLinuxTests((type(of: self)).allTests))
|
||||
}
|
||||
@ -26,7 +48,9 @@ final class HTMLOutputFormatTests: SplashTestCase {
|
||||
extension HTMLOutputFormatTests {
|
||||
static var allTests: [(String, TestClosure<HTMLOutputFormatTests>)] {
|
||||
return [
|
||||
("testStrippingGreaterAndLessThanCharactersFromOutput", testStrippingGreaterAndLessThanCharactersFromOutput)
|
||||
("testBasicGeneration", testBasicGeneration),
|
||||
("testStrippingGreaterAndLessThanCharactersFromOutput", testStrippingGreaterAndLessThanCharactersFromOutput),
|
||||
("testCommentMerging", testCommentMerging)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user