From 6dff287cd2e86db2c8638b6defe6dbc0ad0845b3 Mon Sep 17 00:00:00 2001 From: John Sundell Date: Sun, 10 Mar 2019 13:56:13 +0100 Subject: [PATCH] HTMLOutputFormat: Merge same-type tokens along with whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 elements. Now it’s just one! --- Sources/Splash/Output/HTMLOutputFormat.swift | 40 +++++++++++++++++-- Sources/Splash/Output/OutputBuilder.swift | 2 +- .../Tests/HTMLOutputFormatTests.swift | 26 +++++++++++- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/Sources/Splash/Output/HTMLOutputFormat.swift b/Sources/Splash/Output/HTMLOutputFormat.swift index 2f2e71f..69f0aa7 100644 --- a/Sources/Splash/Output/HTMLOutputFormat.swift +++ b/Sources/Splash/Output/HTMLOutputFormat.swift @@ -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("\(token.escaped)") + 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(""" + \(pending.string.escaped) + """) + + pendingToken = nil + } + + if let whitespace = pendingWhitespace { + html.append(whitespace) + pendingWhitespace = nil + } + } } } diff --git a/Sources/Splash/Output/OutputBuilder.swift b/Sources/Splash/Output/OutputBuilder.swift index 85d10cb..8dcaee9 100644 --- a/Sources/Splash/Output/OutputBuilder.swift +++ b/Sources/Splash/Output/OutputBuilder.swift @@ -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 } diff --git a/Tests/SplashTests/Tests/HTMLOutputFormatTests.swift b/Tests/SplashTests/Tests/HTMLOutputFormatTests.swift index 885b040..7f18b38 100644 --- a/Tests/SplashTests/Tests/HTMLOutputFormatTests.swift +++ b/Tests/SplashTests/Tests/HTMLOutputFormatTests.swift @@ -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, """ + public struct Test: SomeProtocol { + func hello() -> Int { return 7 } + } + """) + } + func testStrippingGreaterAndLessThanCharactersFromOutput() { let html = highlighter.highlight("Array") @@ -18,6 +32,14 @@ final class HTMLOutputFormatTests: SplashTestCase { """) } + func testCommentMerging() { + let html = highlighter.highlight("// Hey I'm a comment!") + + XCTAssertEqual(html, """ + // Hey I'm a comment! + """) + } + func testAllTestsRunOnLinux() { XCTAssertTrue(TestCaseVerifier.verifyLinuxTests((type(of: self)).allTests)) } @@ -26,7 +48,9 @@ final class HTMLOutputFormatTests: SplashTestCase { extension HTMLOutputFormatTests { static var allTests: [(String, TestClosure)] { return [ - ("testStrippingGreaterAndLessThanCharactersFromOutput", testStrippingGreaterAndLessThanCharactersFromOutput) + ("testBasicGeneration", testBasicGeneration), + ("testStrippingGreaterAndLessThanCharactersFromOutput", testStrippingGreaterAndLessThanCharactersFromOutput), + ("testCommentMerging", testCommentMerging) ] } }