A few minor syntax highlighting fixes (#121)

* Correctly highlight nil when used within a ternary operation
* Correctly highlight comments placed next to array types or literals
* Correctly highlight underscores used to ignore function parameters
* Correctly highlight projected property wrapper values
This commit is contained in:
John Sundell 2020-11-14 19:20:35 +01:00 committed by GitHub
parent 81de038955
commit 43bd50bd04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 128 additions and 17 deletions

View File

@ -57,6 +57,8 @@ public struct SwiftGrammar: Grammar {
return false
case ("{", "/"), ("}", "/"):
return false
case ("[", "/"), ("]", "/"):
return false
case (">", "/"), ("?", "/"):
return false
default:
@ -329,6 +331,10 @@ private extension SwiftGrammar {
var tokenType: TokenType { return .keyword }
func matches(_ segment: Segment) -> Bool {
if segment.tokens.current == "_" {
return true
}
if segment.tokens.current == "prefix" && segment.tokens.next == "func" {
return true
}
@ -339,16 +345,7 @@ private extension SwiftGrammar {
}
}
if segment.tokens.next == ":" {
// Nil pattern matching inside of a switch statement case
if segment.tokens.current == "nil" {
guard let previousToken = segment.tokens.previous else {
return false
}
return previousToken.isAny(of: "case", ",")
}
if segment.tokens.next == ":", segment.tokens.current != "nil" {
guard segment.tokens.current == "default" else {
return false
}
@ -379,7 +376,7 @@ private extension SwiftGrammar {
}
// Don't highlight most keywords when used as a parameter label
if !segment.tokens.current.isAny(of: "_", "self", "let", "var", "true", "false", "inout", "nil", "try") {
if !segment.tokens.current.isAny(of: "self", "let", "var", "true", "false", "inout", "nil", "try") {
guard !previousToken.isAny(of: "(", ",", ">(") else {
return false
}
@ -504,6 +501,18 @@ private extension SwiftGrammar {
var tokenType: TokenType { return .property }
func matches(_ segment: Segment) -> Bool {
let currentToken = segment.tokens.current
if currentToken.first == "$" {
let secondIndex = currentToken.index(after: currentToken.startIndex)
guard secondIndex != currentToken.endIndex else {
return false
}
return currentToken[secondIndex].isLetter
}
guard !segment.tokens.onSameLine.isEmpty else {
return false
}
@ -516,7 +525,7 @@ private extension SwiftGrammar {
return false
}
guard !segment.tokens.current.isAny(of: "self", "init") else {
guard !currentToken.isAny(of: "self", "init") else {
return false
}

View File

@ -322,6 +322,43 @@ final class CommentTests: SyntaxHighlighterTestCase {
])
}
func testCommentsAfterArrayTypes() {
let components = highlighter.highlight("""
struct Model {
var one: [String]//One
var two: [String]/*Two*/
}
""")
XCTAssertEqual(components, [
.token("struct", .keyword),
.whitespace(" "),
.plainText("Model"),
.whitespace(" "),
.plainText("{"),
.whitespace("\n "),
.token("var", .keyword),
.whitespace(" "),
.plainText("one:"),
.whitespace(" "),
.plainText("["),
.token("String", .type),
.plainText("]"),
.token("//One", .comment),
.whitespace("\n "),
.token("var", .keyword),
.whitespace(" "),
.plainText("two:"),
.whitespace(" "),
.plainText("["),
.token("String", .type),
.plainText("]"),
.token("/*Two*/", .comment),
.whitespace("\n"),
.plainText("}")
])
}
func testAllTestsRunOnLinux() {
XCTAssertTrue(TestCaseVerifier.verifyLinuxTests((type(of: self)).allTests))
}
@ -344,7 +381,8 @@ extension CommentTests {
("testCommentsNextToGenericTypeList", testCommentsNextToGenericTypeList),
("testCommentsNextToInitialization", testCommentsNextToInitialization),
("testCommentsNextToProtocolName", testCommentsNextToProtocolName),
("testCommentsAfterOptionalTypes", testCommentsAfterOptionalTypes)
("testCommentsAfterOptionalTypes", testCommentsAfterOptionalTypes),
("testCommentsAfterArrayTypes", testCommentsAfterArrayTypes)
]
}
}

View File

@ -920,6 +920,24 @@ final class DeclarationTests: SyntaxHighlighterTestCase {
])
}
func testFunctionDeclarationWithIgnoredParameter() {
let components = highlighter.highlight("func perform(with _: Void) {}")
XCTAssertEqual(components, [
.token("func", .keyword),
.whitespace(" "),
.plainText("perform(with"),
.whitespace(" "),
.token("_", .keyword),
.plainText(":"),
.whitespace(" "),
.token("Void", .type),
.plainText(")"),
.whitespace(" "),
.plainText("{}")
])
}
func testFunctionDeclarationWithNonEscapedKeywordAsName() {
let components = highlighter.highlight("func get() -> Int { return 7 }")
@ -1354,6 +1372,7 @@ extension DeclarationTests {
("testGenericSubscriptDeclaration", testGenericSubscriptDeclaration),
("testDeferDeclaration", testDeferDeclaration),
("testFunctionDeclarationWithInOutParameter", testFunctionDeclarationWithInOutParameter),
("testFunctionDeclarationWithIgnoredParameter", testFunctionDeclarationWithIgnoredParameter),
("testFunctionDeclarationWithNonEscapedKeywordAsName", testFunctionDeclarationWithNonEscapedKeywordAsName),
("testFunctionDeclarationWithEscapedKeywordAsName", testFunctionDeclarationWithEscapedKeywordAsName),
("testFunctionDeclarationWithPreProcessors", testFunctionDeclarationWithPreProcessors),

View File

@ -201,10 +201,18 @@ final class FunctionCallTests: SyntaxHighlighterTestCase {
])
}
func testCallingFunctionWithProjectedPropertyWrapperValue() {
let components = highlighter.highlight("call(self.$value)")
func testCallingFunctionsWithProjectedPropertyWrapperValues() {
let components = highlighter.highlight("""
call($value)
call(self.$value)
""")
XCTAssertEqual(components, [
.token("call", .call),
.plainText("("),
.token("$value", .property),
.plainText(")"),
.whitespace("\n"),
.token("call", .call),
.plainText("("),
.token("self", .keyword),
@ -214,6 +222,17 @@ final class FunctionCallTests: SyntaxHighlighterTestCase {
])
}
func testCallingFunctionWithInoutProjectedPropertyWrapperValue() {
let components = highlighter.highlight("call(&$value)")
XCTAssertEqual(components, [
.token("call", .call),
.plainText("(&"),
.token("$value", .property),
.plainText(")")
])
}
func testCallingMethodWithSameNameAsKeywordWithTrailingClosureSyntax() {
let components = highlighter.highlight("publisher.catch { error in }")
@ -253,7 +272,8 @@ extension FunctionCallTests {
("testIndentedFunctionCalls", testIndentedFunctionCalls),
("testXCTAssertCalls", testXCTAssertCalls),
("testUsingTryKeywordWithinFunctionCall", testUsingTryKeywordWithinFunctionCall),
("testCallingFunctionWithProjectedPropertyWrapperValue", testCallingFunctionWithProjectedPropertyWrapperValue),
("testCallingFunctionsWithProjectedPropertyWrapperValues", testCallingFunctionsWithProjectedPropertyWrapperValues),
("testCallingFunctionWithInoutProjectedPropertyWrapperValue", testCallingFunctionWithInoutProjectedPropertyWrapperValue),
("testCallingMethodWithSameNameAsKeywordWithTrailingClosureSyntax", testCallingMethodWithSameNameAsKeywordWithTrailingClosureSyntax)
]
}

View File

@ -444,6 +444,30 @@ final class StatementTests: SyntaxHighlighterTestCase {
])
}
func testTernaryOperationContainingNil() {
let components = highlighter.highlight("""
components.queryItems = queryItems.isEmpty ? nil : queryItems
""")
XCTAssertEqual(components, [
.plainText("components."),
.token("queryItems", .property),
.whitespace(" "),
.plainText("="),
.whitespace(" "),
.plainText("queryItems."),
.token("isEmpty", .property),
.whitespace(" "),
.plainText("?"),
.whitespace(" "),
.token("nil", .keyword),
.whitespace(" "),
.plainText(":"),
.whitespace(" "),
.plainText("queryItems")
])
}
func testAllTestsRunOnLinux() {
XCTAssertTrue(TestCaseVerifier.verifyLinuxTests((type(of: self)).allTests))
}
@ -468,7 +492,8 @@ extension StatementTests {
("testForStatementWithContinue", testForStatementWithContinue),
("testRepeatWhileStatement", testRepeatWhileStatement),
("testInitializingTypeWithLeadingUnderscore", testInitializingTypeWithLeadingUnderscore),
("testCallingFunctionWithLeadingUnderscore", testCallingFunctionWithLeadingUnderscore)
("testCallingFunctionWithLeadingUnderscore", testCallingFunctionWithLeadingUnderscore),
("testTernaryOperationContainingNil", testTernaryOperationContainingNil)
]
}
}