diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-07-09 01:55:50 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-07-09 01:55:50 +0200 |
| commit | 6926feead1a7fadb7f5f974996bef8c30b3bfdbe (patch) | |
| tree | 5a16e64f70bea3b9f33220cce5ca524e686dbedf /Map/Business/WmapSyntaxHighlighter/SyntaxHighlighter.swift | |
| parent | c21a68c807dcb84b4ce910ee0f73238a8019ffe9 (diff) | |
Use AST based text editor
Diffstat (limited to 'Map/Business/WmapSyntaxHighlighter/SyntaxHighlighter.swift')
| -rw-r--r-- | Map/Business/WmapSyntaxHighlighter/SyntaxHighlighter.swift | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/Map/Business/WmapSyntaxHighlighter/SyntaxHighlighter.swift b/Map/Business/WmapSyntaxHighlighter/SyntaxHighlighter.swift new file mode 100644 index 0000000..e0aaee7 --- /dev/null +++ b/Map/Business/WmapSyntaxHighlighter/SyntaxHighlighter.swift @@ -0,0 +1,83 @@ +// Copyright (C) 2024 Rubén Beltrán del Río + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see https://map.tranquil.systems. +import AppKit + +extension Wmap { + class SyntaxHighlighter { + private var cachedSyntaxElements: [SyntaxElement] = [] + private var lineToElementsMap: [Int: [SyntaxElement]] = [:] + + func updateSyntaxElements(from parsedMap: [Entity]) { + cachedSyntaxElements = parsedMap.flatMap { $0.syntaxElements } + + // Build line-to-elements mapping for fast lookup + lineToElementsMap.removeAll() + for element in cachedSyntaxElements { + let line = element.range.start.line + lineToElementsMap[line, default: []].append(element) + } + } + + func applySyntaxHighlighting(textStorage: NSTextStorage, range: NSRange) { + // Get the line range that encompasses the edited range + let string = textStorage.string as NSString + let lineRange = string.lineRange(for: range) + + // Apply highlighting to elements that intersect with the line range + for element in cachedSyntaxElements { + // Safely convert string range to NSRange with bounds checking + guard element.range.stringRange.lowerBound <= element.range.stringRange.upperBound, + element.range.stringRange.upperBound <= textStorage.string.endIndex + else { + continue + } + + let nsRange = NSRange(element.range.stringRange, in: textStorage.string) + + // Only process elements that intersect with our update area + guard nsRange.location != NSNotFound, + nsRange.location + nsRange.length <= textStorage.length, + NSIntersectionRange(nsRange, lineRange).length > 0 + else { + continue + } + + let color = colorForSyntaxType(element.type) + textStorage.addAttribute(.foregroundColor, value: color, range: nsRange) + } + } + + private func colorForSyntaxType(_ type: SyntaxType) -> NSColor { + switch type { + case .keyword: + return NSColor.Theme.Syntax.option + case .vertexLabel: + return NSColor.Theme.Syntax.vertex + case .number: + return NSColor.Theme.Syntax.number + case .symbol: + return NSColor.Theme.Syntax.symbol + case .shape: + return NSColor.Theme.Syntax.option + case .text: + return NSColor.Theme.Syntax.text + case .punctuation: + return NSColor.Theme.Syntax.punctuation + case .stageNumber: + return NSColor.Theme.Syntax.option + } + } + } +} |