fix auto-close pairs wrapping, normalize-indentation logic, cleanup

This commit is contained in:
jess 2026-04-06 13:51:17 -07:00
parent 030b38a7a2
commit 5342ddbe5f
1 changed files with 36 additions and 30 deletions

View File

@ -1121,37 +1121,45 @@ struct EditorTextView: NSViewRepresentable {
func textView(_ textView: NSTextView, shouldChangeTextIn range: NSRange, replacementString text: String?) -> Bool { func textView(_ textView: NSTextView, shouldChangeTextIn range: NSRange, replacementString text: String?) -> Bool {
guard let text = text, text.count == 1 else { return true } guard let text = text, text.count == 1 else { return true }
let ch = text.first! let ch = text.first!
let hasSelection = range.length > 0
let closers: [Character: Character] = ["}": "{", ")": "(", "]": "["] // Skip over matching closer when cursor is right before it
if let opener = closers[ch] { if !hasSelection {
let closerChars: Set<Character> = ["}", ")", "]", "\"", "'"]
if closerChars.contains(ch) {
let str = textView.string as NSString let str = textView.string as NSString
if range.location < str.length { if range.location < str.length {
let next = str.character(at: range.location) let next = Character(UnicodeScalar(str.character(at: range.location))!)
if next == ch.asciiValue.map({ UInt16($0) }) ?? 0 { if next == ch {
textView.setSelectedRange(NSRange(location: range.location + 1, length: 0)) textView.setSelectedRange(NSRange(location: range.location + 1, length: 0))
return false return false
} }
} }
} }
}
let pairs: [Character: String] = ["{": "}", "(": ")", "[": "]"] let pairClosers: [Character: Character] = ["{": "}", "(": ")", "[": "]"]
if let close = pairs[ch] { if let close = pairClosers[ch] {
textView.insertText(String(ch) + close, replacementRange: range) if hasSelection {
let selected = (textView.string as NSString).substring(with: range)
textView.insertText(String(ch) + selected + String(close), replacementRange: range)
textView.setSelectedRange(NSRange(location: range.location + 1, length: selected.count))
} else {
textView.insertText(String(ch) + String(close), replacementRange: range)
textView.setSelectedRange(NSRange(location: range.location + 1, length: 0)) textView.setSelectedRange(NSRange(location: range.location + 1, length: 0))
}
return false return false
} }
if ch == "\"" || ch == "'" { if ch == "\"" || ch == "'" {
let str = textView.string as NSString if hasSelection {
if range.location < str.length { let selected = (textView.string as NSString).substring(with: range)
let next = str.character(at: range.location) textView.insertText(String(ch) + selected + String(ch), replacementRange: range)
if next == ch.asciiValue.map({ UInt16($0) }) ?? 0 { textView.setSelectedRange(NSRange(location: range.location + 1, length: selected.count))
textView.setSelectedRange(NSRange(location: range.location + 1, length: 0)) } else {
return false
}
}
textView.insertText(String(ch) + String(ch), replacementRange: range) textView.insertText(String(ch) + String(ch), replacementRange: range)
textView.setSelectedRange(NSRange(location: range.location + 1, length: 0)) textView.setSelectedRange(NSRange(location: range.location + 1, length: 0))
}
return false return false
} }
@ -1207,17 +1215,16 @@ struct EditorTextView: NSViewRepresentable {
continue continue
} }
let closesFirst = trimmed.hasPrefix("}") || trimmed.hasPrefix(")") || trimmed.hasPrefix("]") let opens = trimmed.filter { "{([".contains($0) }.count
if closesFirst && depth > 0 { depth -= 1 } let closes = trimmed.filter { "})]".contains($0) }.count
let delta = opens - closes
if delta < 0 { depth = max(0, depth + delta) }
let indent = String(repeating: " ", count: depth) let indent = String(repeating: " ", count: depth)
result.append(indent + trimmed) result.append(indent + trimmed)
let opens = trimmed.filter { "{([".contains($0) }.count if delta > 0 { depth += delta }
let closes = trimmed.filter { "})]".contains($0) }.count
depth += opens - closes
if closesFirst { depth += 1; depth -= 1 }
if depth < 0 { depth = 0 }
} }
return result.joined(separator: "\n") return result.joined(separator: "\n")
@ -1244,14 +1251,13 @@ struct EditorTextView: NSViewRepresentable {
indent += " " indent += " "
} }
let cursorBeforeLineEnd = cursor < NSMaxRange(lineRange) - 1
let charBeforeCursor: Character? = cursor > 0 ? Character(UnicodeScalar(str.character(at: cursor - 1))!) : nil let charBeforeCursor: Character? = cursor > 0 ? Character(UnicodeScalar(str.character(at: cursor - 1))!) : nil
let charAtCursor: Character? = cursor < str.length ? Character(UnicodeScalar(str.character(at: cursor))!) : nil let charAtCursor: Character? = cursor < str.length ? Character(UnicodeScalar(str.character(at: cursor))!) : nil
// Between matching pairs: insert extra newline // Between matching pairs: insert extra newline
if let before = charBeforeCursor, let after = charAtCursor, if let before = charBeforeCursor, let after = charAtCursor,
(before == "{" && after == "}") || (before == "(" && after == ")") || (before == "[" && after == "]") { (before == "{" && after == "}") || (before == "(" && after == ")") || (before == "[" && after == "]") {
let baseIndent = String(indent.dropLast(4).isEmpty ? "" : indent.dropLast(4)) let baseIndent = indent.count >= 4 ? String(indent.dropLast(4)) : ""
let insertion = "\n" + indent + "\n" + baseIndent let insertion = "\n" + indent + "\n" + baseIndent
textView.insertText(insertion, replacementRange: textView.selectedRange()) textView.insertText(insertion, replacementRange: textView.selectedRange())
textView.setSelectedRange(NSRange(location: cursor + 1 + indent.count, length: 0)) textView.setSelectedRange(NSRange(location: cursor + 1 + indent.count, length: 0))