Skip to content

Commit

Permalink
Fix crash in JSONTextView when working with emoji
Browse files Browse the repository at this point in the history
  • Loading branch information
kean committed Dec 18, 2022
1 parent 495018d commit 77c58cd
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 43 deletions.
46 changes: 20 additions & 26 deletions App/macOS/RichTextViewPro/JSONTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ final class JSONTextView: NSTextView {
let substring = textStorage!.attributedSubstring(from: NSRange(location: index, length: 1))
return (index, substring)
}

private func removeCurrentHighlight() {
if let highlightedNode = highlightedNode {
highlightedNode.items.forEach(removeHighlight)
Expand Down Expand Up @@ -138,7 +138,7 @@ final class JSONTextView: NSTextView {
}
}
}

// MARK: Menu

func makeMenu(_ menu: NSMenu, for event: NSEvent, at charIndex: Int) -> NSMenu? {
Expand All @@ -149,7 +149,7 @@ final class JSONTextView: NSTextView {
let menu = NSMenu()

let isObject = context.node is JSONObjectNode

let copyObjectItem = NSMenuItem(title: "Copy \(isObject ? "Object" : "Array")", action: #selector(buttonCopyNodeClicked(_:)), keyEquivalent: "")
copyObjectItem.image = NSImage(systemSymbolName: "doc.on.doc", accessibilityDescription: nil)
copyObjectItem.representedObject = context
Expand All @@ -176,7 +176,7 @@ final class JSONTextView: NSTextView {
focusItem.target = self
menu.addItem(focusItem)
}

let point = convert(event.locationInWindow, from: nil)
menu.popUp(positioning: nil, at: point, in: superview)
}
Expand Down Expand Up @@ -246,36 +246,30 @@ final class JSONTextView: NSTextView {

return findCharater(matchingCharacter, in: string, for: node, startingIndex: index, isForward: isForward)
}

private func findCharater(_ character: String, in string: NSAttributedString, for node: JSONContainerNode, startingIndex: Int, isForward: Bool) -> (Int, NSAttributedString) {
var index = startingIndex

var s: [Character]
if let cache = jsonTextCachedCharacterArray, cache.1 == string, cache.2 == string.length {
s = cache.0
} else {
s = Array(string.string)
jsonTextCachedCharacterArray = (s, string, string.length)
}

let ch = Character(character)

private func findCharater(_ character: String, in attributedString: NSAttributedString, for node: JSONContainerNode, startingIndex: Int, isForward: Bool) -> (Int, NSAttributedString) {
let string = attributedString.string
var index = string.index(string.startIndex, offsetBy: startingIndex)
let character = Character(character)
while true {
index += (isForward ? 1 : -1)
guard s[index] == ch else {
index = isForward ? string.index(after: index) : string.index(before: index)
guard index >= string.startIndex && index <= string.endIndex else {
fatalError("Failed to find matching opening/closing node")
}
guard string[index] == character else {
continue
}
let substring = string.attributedSubstring(from: NSRange(location: index, length: 1))
if substring.string == character,
let matchingNode = substring.attribute(.node, at: 0, effectiveRange: nil) as? JSONContainerNode,
matchingNode === node {
return (index, substring)
// Convert back from Swift.String to NSString range
let range = NSRange(index..<string.index(after: index), in: string)
let substring = attributedString.attributedSubstring(from: range)
assert(substring.string == String(character))
if let matchingNode = substring.attribute(.node, at: 0, effectiveRange: nil) as? JSONContainerNode, matchingNode === node {
return (range.location, substring)
}
}
}
}

var jsonTextCachedCharacterArray: ([Character], NSAttributedString, Int)?

final class JSONLayoutManager: NSLayoutManager {
override func drawUnderline(forGlyphRange glyphRange: NSRange,
underlineType underlineVal: NSUnderlineStyle,
Expand Down
2 changes: 0 additions & 2 deletions App/macOS/RichTextViewPro/RichTextViewPro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,6 @@ final class RichTextViewModelPro: ObservableObject {
}

private func didChangeOriginalText() {
jsonTextCachedCharacterArray = nil
cachedSplitLines = nil
refresh()
refreshLineNumbers()
Expand Down Expand Up @@ -530,7 +529,6 @@ final class RichTextViewModelPro: ObservableObject {
textView?.attributedText = output
isShowingFilteredResults = true
refreshLineNumbers()
jsonTextCachedCharacterArray = nil
} else {
if isShowingFilteredResults {
textView?.attributedText = NSMutableAttributedString(attributedString: sourceText)
Expand Down
4 changes: 2 additions & 2 deletions PulsePro.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.1;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.kean.pulse-pro";
PRODUCT_NAME = "Pulse Pro";
SDKROOT = macosx;
Expand All @@ -1304,7 +1304,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.0.1;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.kean.pulse-pro";
PRODUCT_NAME = "Pulse Pro";
SDKROOT = macosx;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
{
"object": {
"pins": [
{
"package": "swift-log",
"repositoryURL": "https://github.com/apple/swift-log.git",
"state": {
"branch": null,
"revision": "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
"version": "1.4.2"
}
"pins" : [
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
"version" : "1.4.2"
}
]
},
"version": 1
}
],
"version" : 2
}

0 comments on commit 77c58cd

Please sign in to comment.