Skip to content

Commit 0c15df1

Browse files
zhutaozhutao
authored andcommitted
fix crash: NSInvalidArgumentException in CoreText attributed string rendering
Replace NSAttributedString.size()/.draw() with NSString equivalents in LimitRingRenderer readout path, add empty-state guards in MinimalRenderer, and use NSColor.white.withAlphaComponent for safer color creation. Crash was: CTLineCreateWithAttributedString -> TAttributes::ApplyFont -> NSDictionary copyItems encounters nil object, SIGABRT. All 9 crashes on 5/4-5/5 share this root cause in LimitRingRenderer.drawReadout.
1 parent 020dba1 commit 0c15df1

2 files changed

Lines changed: 30 additions & 18 deletions

File tree

resources/icon.png

1.3 MB
Loading

tools/codex-pet-limit-rings.swift

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -752,13 +752,14 @@ struct LimitRingRenderer {
752752
context.addPath(path)
753753
context.strokePath()
754754

755-
let attrs: [NSAttributedString.Key: Any] = [
756-
.font: NSFont.monospacedSystemFont(ofSize: 11.5, weight: .semibold),
757-
.foregroundColor: NSColor(calibratedWhite: 1.0, alpha: 0.92)
755+
let readoutFont = NSFont.monospacedSystemFont(ofSize: 11.5, weight: .semibold)
756+
let readoutAttrs: [NSAttributedString.Key: Any] = [
757+
.font: readoutFont,
758+
.foregroundColor: NSColor.white.withAlphaComponent(0.92)
758759
]
759-
let attributed = NSAttributedString(string: readout.text, attributes: attrs)
760-
let textSize = attributed.size()
761-
attributed.draw(at: CGPoint(x: readout.labelRect.midX - textSize.width / 2, y: readout.labelRect.midY - textSize.height / 2 + 0.5))
760+
let text = readout.text as NSString
761+
let textSize = text.size(withAttributes: readoutAttrs)
762+
text.draw(at: CGPoint(x: readout.labelRect.midX - textSize.width / 2, y: readout.labelRect.midY - textSize.height / 2 + 0.5), withAttributes: readoutAttrs)
762763
context.restoreGState()
763764
}
764765

@@ -869,9 +870,10 @@ struct LimitBarRenderer {
869870
let textGap: CGFloat = 6.0
870871
let barWidth = rect.width
871872

873+
let barTextFont = NSFont.monospacedSystemFont(ofSize: 9.5, weight: .medium)
872874
let textAttrs: [NSAttributedString.Key: Any] = [
873-
.font: NSFont.monospacedSystemFont(ofSize: 9.5, weight: .medium),
874-
.foregroundColor: NSColor(calibratedWhite: 1.0, alpha: 0.82)
875+
.font: barTextFont,
876+
.foregroundColor: NSColor.white.withAlphaComponent(0.82)
875877
]
876878

877879
var cursorY = rect.height
@@ -992,33 +994,43 @@ struct MinimalRenderer {
992994
var colorScheme: ColorScheme = .warm
993995

994996
func draw(in rect: CGRect) {
997+
guard state.primary != nil || state.secondary != nil else { return }
995998
guard let context = NSGraphicsContext.current?.cgContext else { return }
996999
context.saveGState()
9971000
context.setShouldAntialias(true)
9981001
context.clear(rect)
9991002

1000-
let combined = NSMutableAttributedString()
1001-
let sepAttrs: [NSAttributedString.Key: Any] = [
1002-
.font: NSFont.monospacedSystemFont(ofSize: 11, weight: .regular),
1003-
.foregroundColor: NSColor(calibratedWhite: 1.0, alpha: 0.25)
1004-
]
1003+
let boldFont = NSFont.monospacedSystemFont(ofSize: 12, weight: .bold)
1004+
let sepFont = NSFont.monospacedSystemFont(ofSize: 11, weight: .regular)
10051005

1006+
var parts: [(text: String, attrs: [NSAttributedString.Key: Any])] = []
10061007
if let primary = state.primary {
10071008
let attrs: [NSAttributedString.Key: Any] = [
1008-
.font: NSFont.monospacedSystemFont(ofSize: 12, weight: .bold),
1009+
.font: boldFont,
10091010
.foregroundColor: color(forRemaining: primary.remainingPercent)
10101011
]
1011-
combined.append(NSAttributedString(string: formatPercent(primary.remainingPercent), attributes: attrs))
1012+
parts.append((formatPercent(primary.remainingPercent), attrs))
10121013
}
10131014
if state.primary != nil && state.secondary != nil {
1014-
combined.append(NSAttributedString(string: " ", attributes: sepAttrs))
1015+
let attrs: [NSAttributedString.Key: Any] = [
1016+
.font: sepFont,
1017+
.foregroundColor: NSColor.white.withAlphaComponent(0.25)
1018+
]
1019+
parts.append((" ", attrs))
10151020
}
10161021
if let secondary = state.secondary {
10171022
let attrs: [NSAttributedString.Key: Any] = [
1018-
.font: NSFont.monospacedSystemFont(ofSize: 12, weight: .bold),
1023+
.font: boldFont,
10191024
.foregroundColor: color(forRemaining: secondary.remainingPercent)
10201025
]
1021-
combined.append(NSAttributedString(string: formatPercent(secondary.remainingPercent), attributes: attrs))
1026+
parts.append((formatPercent(secondary.remainingPercent), attrs))
1027+
}
1028+
1029+
guard !parts.isEmpty else { context.restoreGState(); return }
1030+
1031+
let combined = NSMutableAttributedString()
1032+
for part in parts {
1033+
combined.append(NSAttributedString(string: part.text, attributes: part.attrs))
10221034
}
10231035

10241036
let textSize = combined.size()

0 commit comments

Comments
 (0)