class MapTextEditorController: NSViewController {
@Binding var text: String
+ var colorScheme: ColorScheme
- init(text: Binding<String>) {
+ private let vertexRegex = MapParsingPatterns.vertex
+ private let edgeRegex = MapParsingPatterns.edge
+ private let blockerRegex = MapParsingPatterns.blocker
+ private let opportunityRegex = MapParsingPatterns.opportunity
+ private let stageRegex = MapParsingPatterns.stage
+
+ private let debouncer: Debouncer = Debouncer(seconds: 0.2)
+
+ init(text: Binding<String>, colorScheme: ColorScheme) {
self._text = text
+ self.colorScheme = colorScheme
super.init(nibName: nil, bundle: nil)
}
scrollView.translatesAutoresizingMaskIntoConstraints = false
textView.delegate = self
+ textView.textStorage?.delegate = self
textView.string = self.text
textView.isEditable = true
textView.font = .monospacedSystemFont(ofSize: 16.0, weight: .regular)
override func viewDidAppear() {
self.view.window?.makeFirstResponder(self.view)
}
+
+ func updateColorScheme(_ colorScheme: ColorScheme) {
+ self.colorScheme = colorScheme
+ }
}
extension MapTextEditorController: NSTextViewDelegate {
}
}
+extension MapTextEditorController: NSTextStorageDelegate {
+ override func textStorageDidProcessEditing(_ obj: Notification) {
+ if let textStorage = obj.object as? NSTextStorage {
+ debouncer.debounce {
+ DispatchQueue.main.async {
+ self.colorizeText(textStorage: textStorage)
+ }
+ }
+ }
+ }
+
+ private func colorizeText(textStorage: NSTextStorage) {
+ let range = NSMakeRange(0, textStorage.length)
+ var matches = vertexRegex.matches(in: textStorage.string, options: [], range: range)
+ let colors = MapColor.colorForScheme(colorScheme)
+
+ for match in matches {
+ textStorage.addAttributes([.foregroundColor: colors.syntax.vertex], range: match.range(at: 1))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.number], range: match.range(at: 2))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.number], range: match.range(at: 3))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.option], range: match.range(at: 4))
+ }
+
+ matches = edgeRegex.matches(in: textStorage.string, options: [], range: range)
+
+ for match in matches {
+ textStorage.addAttributes([.foregroundColor: colors.syntax.vertex], range: match.range(at: 1))
+ let arrowRange = match.range(at: 2)
+ textStorage.addAttributes(
+ [.foregroundColor: colors.syntax.symbol],
+ range: NSMakeRange(arrowRange.lowerBound - 1, arrowRange.length + 1))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.vertex], range: match.range(at: 3))
+ }
+
+ matches = opportunityRegex.matches(in: textStorage.string, options: [], range: range)
+
+ for match in matches {
+ textStorage.addAttributes([.foregroundColor: colors.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.vertex], range: match.range(at: 2))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.symbol], range: match.range(at: 3))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.number], range: match.range(at: 4))
+ }
+
+ matches = blockerRegex.matches(in: textStorage.string, options: [], range: range)
+
+ for match in matches {
+ textStorage.addAttributes([.foregroundColor: colors.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.vertex], range: match.range(at: 2))
+ }
+
+ matches = stageRegex.matches(in: textStorage.string, options: [], range: range)
+
+ for match in matches {
+ textStorage.addAttributes([.foregroundColor: colors.syntax.option], range: match.range(at: 1))
+ textStorage.addAttributes([.foregroundColor: colors.syntax.number], range: match.range(at: 2))
+ }
+ }
+}
+
struct MapTextEditor: NSViewControllerRepresentable {
@Binding var text: String
+ let colorScheme: ColorScheme
func makeNSViewController(
context: NSViewControllerRepresentableContext<MapTextEditor>
) -> MapTextEditorController {
- return MapTextEditorController(text: $text)
+ return MapTextEditorController(text: $text, colorScheme: colorScheme)
}
func updateNSViewController(
_ nsViewController: MapTextEditorController,
context: NSViewControllerRepresentableContext<MapTextEditor>
) {
+ nsViewController.updateColorScheme(context.environment.colorScheme)
}
}