@@ -76,18 +76,21 @@ enum SQLSyntaxHighlighter {
76 let nsText = text as NSString
76 let nsText = text as NSString
77 var protectedRanges: [NSRange] = []
77 var protectedRanges: [NSRange] = []
79− // 1. Comments (-- to end of line)
80− applyRegex(commentRegex, to: textStorage, text: nsText,
81− color: .secondaryLabelColor, protectedRanges: &protectedRanges)
83− // 2. Single-quoted strings
79+ // 1. Single-quoted strings
84 applyRegex(singleQuoteRegex, to: textStorage, text: nsText,
80 applyRegex(singleQuoteRegex, to: textStorage, text: nsText,
85 color: .systemRed, protectedRanges: &protectedRanges)
81 color: .systemRed, protectedRanges: &protectedRanges)
87− // 3. Double-quoted identifiers
83+ // 2. Double-quoted identifiers
88 applyRegex(doubleQuoteRegex, to: textStorage, text: nsText,
84 applyRegex(doubleQuoteRegex, to: textStorage, text: nsText,
89 color: .systemRed, protectedRanges: &protectedRanges)
85 color: .systemRed, protectedRanges: &protectedRanges)
87+ // 3. Comments (-- to end of line). Highlighted AFTER strings, and a `--`
88+ // that begins inside a string literal (protectedRanges currently holds
89+ // only string ranges) is skipped — otherwise `'a--b' AND y = 5` would
90+ // bleed a gray comment over the trailing real SQL.
91+ applyCommentRegex(commentRegex, to: textStorage, text: nsText,
92+ color: .secondaryLabelColor, protectedRanges: &protectedRanges)
91 // 4. Numbers (outside protected ranges)
94 // 4. Numbers (outside protected ranges)
92 applyUnprotectedRegex(numberRegex, to: textStorage, text: nsText,
95 applyUnprotectedRegex(numberRegex, to: textStorage, text: nsText,
93 color: .systemPurple, protectedRanges: protectedRanges)
96 color: .systemPurple, protectedRanges: protectedRanges)
@@ -117,6 +120,32 @@ enum SQLSyntaxHighlighter {
123+ /// Like `applyRegex`, but skips any match whose start falls inside an
124+ /// already-claimed range (used for comments so a `--` inside a string literal
125+ /// doesn't start a comment).
126+ private static func applyCommentRegex(
127+ _ regex: NSRegularExpression,
128+ to textStorage: NSTextStorage,
131+ protectedRanges: inout [NSRange]
133+ let matches = regex.matches(in: text as String, range: NSRange(location: 0, length: text.length))
134+ for match in matches where !isStartProtected(match.range.location, by: protectedRanges) {
135+ textStorage.addAttribute(.foregroundColor, value: color, range: match.range)
136+ protectedRanges.append(match.range)
140+ private static func isStartProtected(_ location: Int, by protectedRanges: [NSRange]) -> Bool {
141+ for protected in protectedRanges {
142+ if location >= protected.location && location < NSMaxRange(protected) {
120 private static func applyUnprotectedRegex(
149 private static func applyUnprotectedRegex(
121 _ regex: NSRegularExpression,
150 _ regex: NSRegularExpression,
122 to textStorage: NSTextStorage,
151 to textStorage: NSTextStorage,