I have a syntax highlighting App that usually works fine but the auto brackets closing part doesn’t work. When I type ( it add ) but I can’t delete that, however when I move the cursor I somehow can delete them.
I tried everything I could but wasn’t able to fix it. Feel free to change the whole thing if you want to.
Lexer.swift:
let swiftlexer = [
Keyword(word: "let", color: highlight_pink),
Keyword(word: "var", color: highlight_pink),
Keyword(word: "if", color: highlight_pink),
Keyword(word: "else", color: highlight_pink),
Keyword(word: "for", color: highlight_pink)
]
ContentView.swift:
import SwiftUI
struct Keyword {
var word: String
var color: UIColor
}
let highlight_purple = UIColor(red: 70/255, green: 30/255, blue: 160/255, alpha: 1.0)
let highlight_pink = UIColor(red: 160/255, green: 30/255, blue: 160/255, alpha: 1.0)
let highlight_number = UIColor(red: 0/255, green: 0/255, blue: 255/255, alpha: 1.0)
let highlight_string = UIColor(red: 190/255, green: 60/255, blue: 40/255, alpha: 1.0)
var keywords = swiftlexer
// variable is predefined and works fine
class TextColorUpdater: ObservableObject {
@Published var attributedText: NSAttributedString
init(initialText: String) {
self.attributedText = TextColorUpdater.highlightText(initialText)
}
func addClosingParenthesis() {
// let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
// mutableAttributedString.append(NSAttributedString(string: ")"))
attributedText = TextColorUpdater.highlightText(attributedText.string + ")")
update()
}
func update() {
self.attributedText = TextColorUpdater.highlightText(attributedText.string)
}
static func highlightText(_ text: String) -> NSAttributedString {
let mutableAttributedString = NSMutableAttributedString(string: text)
mutableAttributedString.addAttribute(.font, value: UIFont(name: "Menlo", size: 25) as Any, range: NSRange(location: 0, length: mutableAttributedString.length))
// Regular expression for detecting numbers (including decimal numbers)
if let regex = try? NSRegularExpression(pattern: "\\b(\\d+\\.?\\d*)\\b", options: .caseInsensitive) {
let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
for match in matches {
let nsRange = match.range
mutableAttributedString.addAttribute(.foregroundColor, value: highlight_number, range: nsRange)
}
}
if let stringRegex = try? NSRegularExpression(pattern: "\"([^\"]*)\"", options: .caseInsensitive) {
let stringMatches = stringRegex.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
for match in stringMatches {
let quoteRange = match.range(at: 0)
let textRange = match.range(at: 1)
mutableAttributedString.addAttribute(.foregroundColor, value: highlight_string, range: quoteRange)
mutableAttributedString.addAttribute(.foregroundColor, value: highlight_string, range: textRange)
}
}
for keyword in keywords {
if let regex = try? NSRegularExpression(pattern: "\\b\(keyword.word)\\b", options: .caseInsensitive) {
let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
for match in matches {
let nsRange = match.range
mutableAttributedString.addAttribute(.foregroundColor, value: keyword.color, range: nsRange)
}
}
}
return mutableAttributedString
}
}
struct HighlightedTextEditor: UIViewRepresentable {
@Binding var attributedText: NSAttributedString
@MainActor
class Coordinator: NSObject, UITextViewDelegate {
let textView = UITextView()
var textDidChange: ((NSAttributedString) -> Void)?
override init() {
super.init()
textView.isEditable = true
textView.keyboardType = .asciiCapable
textView.isSelectable = true
textView.delegate = self
}
func textViewDidChange(_ textView: UITextView) {
textDidChange?(textView.attributedText)
}
}
func makeUIView(context: Context) -> UITextView {
context.coordinator.textView
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.attributedText = attributedText
context.coordinator.textDidChange = { attributedText = $0 }
}
}
struct ContentView: View {
@StateObject var textColorUpdater = TextColorUpdater(initialText: "")
@State private var oldText = ""
var body: some View {
VStack {
HighlightedTextEditor(attributedText: $textColorUpdater.attributedText)
.onChange(of: textColorUpdater.attributedText, {
let newString = textColorUpdater.attributedText.string
if newString.last == "(" {
textColorUpdater.addClosingParenthesis()
}
textColorUpdater.update()
oldText = newString
})
}
}
}
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}