UI: macOS: Fix UTF-8 and UTF-16 conversions in highlighter code

NSString uses UTF-16 internally, while String uses UTF-8 in Swift 5.

Signed-off-by: Andrej Mihajlov <and@mullvad.net>
This commit is contained in:
Andrej Mihajlov 2020-12-15 18:26:55 +01:00 committed by Jason A. Donenfeld
parent 403ee63615
commit 9269c7c1c1
2 changed files with 25 additions and 9 deletions

View File

@ -67,7 +67,7 @@ class ConfTextStorage: NSTextStorage {
override func replaceCharacters(in range: NSRange, with str: String) { override func replaceCharacters(in range: NSRange, with str: String) {
beginEditing() beginEditing()
backingStore.replaceCharacters(in: range, with: str) backingStore.replaceCharacters(in: range, with: str)
edited(.editedCharacters, range: range, changeInLength: str.count - range.length) edited(.editedCharacters, range: range, changeInLength: str.utf16.count - range.length)
endEditing() endEditing()
} }
@ -94,6 +94,7 @@ class ConfTextStorage: NSTextStorage {
func evaluateExcludePrivateIPs(highlightSpans: UnsafePointer<highlight_span>) { func evaluateExcludePrivateIPs(highlightSpans: UnsafePointer<highlight_span>) {
var spans = highlightSpans var spans = highlightSpans
let string = backingStore.string
enum FieldType: String { enum FieldType: String {
case dns case dns
case allowedips case allowedips
@ -102,7 +103,7 @@ class ConfTextStorage: NSTextStorage {
resetLastPeer() resetLastPeer()
while spans.pointee.type != HighlightEnd { while spans.pointee.type != HighlightEnd {
let span = spans.pointee let span = spans.pointee
var substring = backingStore.attributedSubstring(from: NSRange(location: span.start, length: span.len)).string.lowercased() var substring = String(string.substring(higlightSpan: span)).lowercased()
if span.type == HighlightError { if span.type == HighlightError {
resetLastPeer() resetLastPeer()
@ -123,8 +124,9 @@ class ConfTextStorage: NSTextStorage {
let next = spans.successor() let next = spans.successor()
let nextnext = next.successor() let nextnext = next.successor()
if next.pointee.type == HighlightDelimiter && nextnext.pointee.type == HighlightCidr { if next.pointee.type == HighlightDelimiter && nextnext.pointee.type == HighlightCidr {
substring += backingStore.attributedSubstring(from: NSRange(location: next.pointee.start, length: next.pointee.len)).string + let delimiter = string.substring(higlightSpan: next.pointee)
backingStore.attributedSubstring(from: NSRange(location: nextnext.pointee.start, length: nextnext.pointee.len)).string let cidr = string.substring(higlightSpan: nextnext.pointee)
substring += delimiter + cidr
} }
lastOnePeerAllowedIPs.append(substring) lastOnePeerAllowedIPs.append(substring)
} else if span.type == HighlightPublicKey { } else if span.type == HighlightPublicKey {
@ -139,7 +141,8 @@ class ConfTextStorage: NSTextStorage {
hasError = false hasError = false
privateKeyString = nil privateKeyString = nil
let fullTextRange = NSRange(location: 0, length: (backingStore.string as NSString).length) let string = backingStore.string
let fullTextRange = NSRange(..<string.endIndex, in: string)
backingStore.beginEditing() backingStore.beginEditing()
let defaultAttributes: [NSAttributedString.Key: Any] = [ let defaultAttributes: [NSAttributedString.Key: Any] = [
@ -147,15 +150,19 @@ class ConfTextStorage: NSTextStorage {
.font: defaultFont .font: defaultFont
] ]
backingStore.setAttributes(defaultAttributes, range: fullTextRange) backingStore.setAttributes(defaultAttributes, range: fullTextRange)
var spans = highlight_config(backingStore.string)! var spans = highlight_config(string)!
evaluateExcludePrivateIPs(highlightSpans: spans) evaluateExcludePrivateIPs(highlightSpans: spans)
let spansStart = spans let spansStart = spans
while spans.pointee.type != HighlightEnd { while spans.pointee.type != HighlightEnd {
let span = spans.pointee let span = spans.pointee
let range = NSRange(location: span.start, length: span.len) let startIndex = string.utf8.index(string.startIndex, offsetBy: span.start)
let endIndex = string.utf8.index(startIndex, offsetBy: span.len)
let range = NSRange(startIndex..<endIndex, in: string)
backingStore.setAttributes(nonColorAttributes(for: span.type), range: range) backingStore.setAttributes(nonColorAttributes(for: span.type), range: range)
let color = textColorTheme.colorMap[span.type.rawValue, default: textColorTheme.defaultColor] let color = textColorTheme.colorMap[span.type.rawValue, default: textColorTheme.defaultColor]
backingStore.addAttribute(.foregroundColor, value: color, range: range) backingStore.addAttribute(.foregroundColor, value: color, range: range)
@ -164,7 +171,7 @@ class ConfTextStorage: NSTextStorage {
} }
if span.type == HighlightPrivateKey { if span.type == HighlightPrivateKey {
privateKeyString = backingStore.attributedSubstring(from: NSRange(location: span.start, length: span.len)).string privateKeyString = String(string.substring(higlightSpan: span))
} }
spans = spans.successor() spans = spans.successor()
@ -178,3 +185,12 @@ class ConfTextStorage: NSTextStorage {
} }
} }
private extension String {
func substring(higlightSpan span: highlight_span) -> Substring {
let startIndex = self.utf8.index(self.utf8.startIndex, offsetBy: span.start)
let endIndex = self.utf8.index(startIndex, offsetBy: span.len)
return self[startIndex..<endIndex]
}
}

View File

@ -70,7 +70,7 @@ class ConfTextView: NSTextView {
} }
func setConfText(_ text: String) { func setConfText(_ text: String) {
let fullTextRange = NSRange(location: 0, length: (string as NSString).length) let fullTextRange = NSRange(..<string.endIndex, in: string)
if shouldChangeText(in: fullTextRange, replacementString: text) { if shouldChangeText(in: fullTextRange, replacementString: text) {
replaceCharacters(in: fullTextRange, with: text) replaceCharacters(in: fullTextRange, with: text)
didChangeText() didChangeText()