Skip to content

Commit f421fcb

Browse files
committed
wip
1 parent 70a02f0 commit f421fcb

File tree

2 files changed

+76
-25
lines changed

2 files changed

+76
-25
lines changed

TablePro/Core/Autocomplete/SQLContextAnalyzer.swift

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,34 @@ final class SQLContextAnalyzer {
135135
}
136136
}()
137137

138-
/// Pre-compiled regex for removing strings and comments
139-
private static let singleQuoteStringRegex = try! NSRegularExpression(pattern: "'[^']*'")
140-
private static let doubleQuoteStringRegex = try! NSRegularExpression(pattern: "\"[^\"]*\"")
141-
private static let blockCommentRegex = try! NSRegularExpression(pattern: "/\\*[\\s\\S]*?\\*/")
142-
private static let lineCommentRegex = try! NSRegularExpression(pattern: "--[^\n]*")
138+
/// Pre-compiled regex for removing strings and comments (force-unwrap safe: simple patterns)
139+
private static let singleQuoteStringRegex: NSRegularExpression = {
140+
guard let regex = try? NSRegularExpression(pattern: "'[^']*'") else {
141+
fatalError("Failed to compile singleQuoteStringRegex - invalid pattern")
142+
}
143+
return regex
144+
}()
145+
146+
private static let doubleQuoteStringRegex: NSRegularExpression = {
147+
guard let regex = try? NSRegularExpression(pattern: "\"[^\"]*\"") else {
148+
fatalError("Failed to compile doubleQuoteStringRegex - invalid pattern")
149+
}
150+
return regex
151+
}()
152+
153+
private static let blockCommentRegex: NSRegularExpression = {
154+
guard let regex = try? NSRegularExpression(pattern: "/\\*[\\s\\S]*?\\*/") else {
155+
fatalError("Failed to compile blockCommentRegex - invalid pattern")
156+
}
157+
return regex
158+
}()
159+
160+
private static let lineCommentRegex: NSRegularExpression = {
161+
guard let regex = try? NSRegularExpression(pattern: "--[^\n]*") else {
162+
fatalError("Failed to compile lineCommentRegex - invalid pattern")
163+
}
164+
return regex
165+
}()
143166

144167
// MARK: - Main Analysis
145168

@@ -624,21 +647,29 @@ final class SQLContextAnalyzer {
624647
var result = text
625648

626649
// Use pre-compiled regex patterns for performance
627-
if let regex = Self.singleQuoteStringRegex {
628-
result = regex.stringByReplacingMatches(in: result, range: NSRange(result.startIndex..., in: result), withTemplate: "''")
629-
}
650+
result = Self.singleQuoteStringRegex.stringByReplacingMatches(
651+
in: result,
652+
range: NSRange(result.startIndex..., in: result),
653+
withTemplate: "''"
654+
)
630655

631-
if let regex = Self.doubleQuoteStringRegex {
632-
result = regex.stringByReplacingMatches(in: result, range: NSRange(result.startIndex..., in: result), withTemplate: "\"\"")
633-
}
656+
result = Self.doubleQuoteStringRegex.stringByReplacingMatches(
657+
in: result,
658+
range: NSRange(result.startIndex..., in: result),
659+
withTemplate: "\"\""
660+
)
634661

635-
if let regex = Self.blockCommentRegex {
636-
result = regex.stringByReplacingMatches(in: result, range: NSRange(result.startIndex..., in: result), withTemplate: "")
637-
}
662+
result = Self.blockCommentRegex.stringByReplacingMatches(
663+
in: result,
664+
range: NSRange(result.startIndex..., in: result),
665+
withTemplate: ""
666+
)
638667

639-
if let regex = Self.lineCommentRegex {
640-
result = regex.stringByReplacingMatches(in: result, range: NSRange(result.startIndex..., in: result), withTemplate: "")
641-
}
668+
result = Self.lineCommentRegex.stringByReplacingMatches(
669+
in: result,
670+
range: NSRange(result.startIndex..., in: result),
671+
withTemplate: ""
672+
)
642673

643674
return result
644675
}

TablePro/Views/Editor/EditorTextView.swift

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ final class EditorTextView: NSTextView {
2424
/// Callback when user clicks at a different position (to dismiss completion)
2525
var onClickOutsideCompletion: (() -> Void)?
2626

27+
/// Track the last cursor position for smart invalidation
28+
private var lastCursorLine: Int = -1
29+
2730
// MARK: - Auto-Pairing Configuration
2831

2932
private let bracketPairs: [Character: Character] = [
@@ -56,9 +59,6 @@ final class EditorTextView: NSTextView {
5659
commonInit()
5760
}
5861

59-
/// Track the last cursor position for smart invalidation
60-
private var lastCursorLine: Int = -1
61-
6262
private func commonInit() {
6363
// Observe selection changes for visual updates
6464
NotificationCenter.default.addObserver(
@@ -150,22 +150,41 @@ final class EditorTextView: NSTextView {
150150
lastCursorLine = currentLine
151151
}
152152

153+
/// Simple cache for line lookups to avoid repeated O(n) scans for consecutive lines
154+
private var lineCache: (lastLine: Int, charIndex: Int, searchRange: NSRange)?
155+
153156
/// Get the rect for a specific line number using efficient NSString lineRange
154157
private func lineRectForLine(_ lineNumber: Int, layoutManager: NSLayoutManager, textContainer: NSTextContainer) -> NSRect? {
155158
guard layoutManager.numberOfGlyphs > 0 else { return nil }
156159

157160
let text = string as NSString
158161
guard text.length > 0 else { return nil }
159162

160-
// Find the character index for the target line using NSString's lineRange
161163
var charIndex = 0
162164
var searchRange = NSRange(location: 0, length: text.length)
165+
var startLine = 0
166+
167+
// Use cache if we're looking for a nearby line (common case: prev/current line)
168+
if let cache = lineCache, abs(cache.lastLine - lineNumber) <= 1 {
169+
if cache.lastLine == lineNumber {
170+
// Exact cache hit
171+
charIndex = cache.charIndex
172+
searchRange = cache.searchRange
173+
startLine = lineNumber
174+
} else if cache.lastLine + 1 == lineNumber {
175+
// Next line after cached (common: moving from prev to current)
176+
charIndex = cache.charIndex
177+
searchRange = cache.searchRange
178+
startLine = cache.lastLine
179+
}
180+
}
163181

164-
// Iterate to the target line
165-
for _ in 0..<lineNumber {
182+
// Iterate from cached position (or start) to the target line
183+
for _ in startLine..<lineNumber {
166184
guard searchRange.location < text.length else {
167185
// Line number is beyond document, clamp to last valid position
168186
charIndex = max(0, text.length - 1)
187+
lineCache = nil // Invalidate cache for out-of-bounds
169188
break
170189
}
171190

@@ -174,11 +193,12 @@ final class EditorTextView: NSTextView {
174193
// Move to next line
175194
searchRange.location = NSMaxRange(lineRange)
176195
searchRange.length = text.length - searchRange.location
177-
178-
// Set charIndex to the start of the next line
179196
charIndex = searchRange.location
180197
}
181198

199+
// Cache the result for next lookup
200+
lineCache = (lineNumber, charIndex, searchRange)
201+
182202
// If we reached the target line, charIndex is already set to its start
183203
// Otherwise it was clamped to the last valid position
184204

0 commit comments

Comments
 (0)