From 7f2421cd997b1c42ccde8a991be120ed589cd02f Mon Sep 17 00:00:00 2001 From: John Sundell Date: Fri, 8 Mar 2019 18:20:36 +0100 Subject: [PATCH] Correctly highlight types conforming to multiple protocols Previously, the last protocol would be treated as a function call (Splash thought it was a call with trailing closure syntax, rather than the opening of a type definition). This patch fixes that by verifying that the code checking for constraints inside a generic type definition is in fact looking at a generic, rather than something else. --- Sources/Splash/Grammar/SwiftGrammar.swift | 10 +++++++++- Tests/SplashTests/Tests/DeclarationTests.swift | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Sources/Splash/Grammar/SwiftGrammar.swift b/Sources/Splash/Grammar/SwiftGrammar.swift index 803c436..3ef2f92 100644 --- a/Sources/Splash/Grammar/SwiftGrammar.swift +++ b/Sources/Splash/Grammar/SwiftGrammar.swift @@ -257,11 +257,19 @@ private extension SwiftGrammar { // In a generic declaration, only highlight constraints if segment.tokens.previous.isAny(of: "<", ",") { + var foundOpeningBracket = false + // Since the declaration might be on another line, we have to walk // backwards through all tokens until we've found enough information. for token in segment.tokens.all.reversed() { + if !foundOpeningBracket && token == "<" { + foundOpeningBracket = true + } + guard !declarationKeywords.contains(token) else { - return false + // If it turns out that we weren't in fact inside of a generic + // declaration, (lacking "<"), then highlight the type as normal. + return !foundOpeningBracket } guard !keywords.contains(token) else { diff --git a/Tests/SplashTests/Tests/DeclarationTests.swift b/Tests/SplashTests/Tests/DeclarationTests.swift index bce347b..feb961f 100644 --- a/Tests/SplashTests/Tests/DeclarationTests.swift +++ b/Tests/SplashTests/Tests/DeclarationTests.swift @@ -221,6 +221,23 @@ final class DeclarationTests: SyntaxHighlighterTestCase { ]) } + func testClassDeclarationWithMultipleProtocolConformances() { + let components = highlighter.highlight("class MyClass: ProtocolA, ProtocolB {}") + + XCTAssertEqual(components, [ + .token("class", .keyword), + .whitespace(" "), + .plainText("MyClass:"), + .whitespace(" "), + .token("ProtocolA", .type), + .plainText(","), + .whitespace(" "), + .token("ProtocolB", .type), + .whitespace(" "), + .plainText("{}") + ]) + } + func testSubclassDeclaration() { let components = highlighter.highlight("class ViewController: UIViewController { }") @@ -616,6 +633,7 @@ extension DeclarationTests { ("testGenericStructDeclaration", testGenericStructDeclaration), ("testClassDeclaration", testClassDeclaration), ("testCompactClassDeclarationWithInitializer", testCompactClassDeclarationWithInitializer), + ("testClassDeclarationWithMultipleProtocolConformances", testClassDeclarationWithMultipleProtocolConformances), ("testSubclassDeclaration", testSubclassDeclaration), ("testProtocolDeclaration", testProtocolDeclaration), ("testExtensionDeclaration", testExtensionDeclaration),