Turn on strict memory safety for the macOS app
This commit is contained in:
+2
-1
@@ -25,7 +25,8 @@ let package = Package(
|
||||
.product(name: "SwiftTerm", package: "SwiftTerm"),
|
||||
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
||||
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
|
||||
]
|
||||
],
|
||||
swiftSettings: [.strictMemorySafety()]
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -277,8 +277,13 @@ struct DiagramLayout {
|
||||
let size: CGSize
|
||||
}
|
||||
|
||||
nonisolated(unsafe) private let labelFont = Fonts.ct(13)
|
||||
nonisolated(unsafe) private let edgeFont = Fonts.ct(12)
|
||||
private var labelFont: CTFont {
|
||||
Fonts.ns(13) as CTFont
|
||||
}
|
||||
|
||||
private var edgeFont: CTFont {
|
||||
Fonts.ns(12) as CTFont
|
||||
}
|
||||
|
||||
func textSize(_ text: String, _ font: CTFont) -> CGSize {
|
||||
let lines = text.components(separatedBy: "\n")
|
||||
|
||||
@@ -26,9 +26,9 @@ private func bytes(_ n: Int64) -> String {
|
||||
return "\(n) B"
|
||||
}
|
||||
if n < 1024 * 1024 {
|
||||
return String(format: "%.1f KiB", Double(n) / 1024)
|
||||
return "\((Double(n) / 1024).formatted(.number.precision(.fractionLength(1)).grouping(.never))) KiB"
|
||||
}
|
||||
return String(format: "%.1f MiB", Double(n) / 1024 / 1024)
|
||||
return "\((Double(n) / 1024 / 1024).formatted(.number.precision(.fractionLength(1)).grouping(.never))) MiB"
|
||||
}
|
||||
|
||||
private func shown(_ c: FileContent) -> Int64 {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import CoreText
|
||||
import Synchronization
|
||||
import SwiftUI
|
||||
|
||||
enum Fonts {
|
||||
@@ -14,7 +15,7 @@ enum Fonts {
|
||||
}()
|
||||
|
||||
private static func file(_ subset: String, _ italic: Bool, _ weight: CGFloat) -> CTFontDescriptor {
|
||||
let d = descriptors["atkinson-hyperlegible-mono-\(subset)-wght-\(italic ? "italic" : "normal").woff2"]!
|
||||
let d = unsafe descriptors["atkinson-hyperlegible-mono-\(subset)-wght-\(italic ? "italic" : "normal").woff2"]!
|
||||
return CTFontDescriptorCreateCopyWithVariation(d, 0x7767_6874 as CFNumber, weight)
|
||||
}
|
||||
|
||||
@@ -24,29 +25,25 @@ enum Fonts {
|
||||
return CTFontCreateWithFontDescriptor(d, size, nil)
|
||||
}
|
||||
|
||||
nonisolated(unsafe) private static var fonts: [String: (font: Font, ns: NSFont)] = [:]
|
||||
private static let lock = NSLock()
|
||||
private static let fonts = Mutex<[String: CTFont]>([:])
|
||||
|
||||
private static func cached(_ size: CGFloat, _ weight: CGFloat, _ italic: Bool) -> (font: Font, ns: NSFont) {
|
||||
private static func cached(_ size: CGFloat, _ weight: CGFloat, _ italic: Bool) -> CTFont {
|
||||
let key = "\(size) \(weight) \(italic)"
|
||||
lock.lock()
|
||||
defer {
|
||||
lock.unlock()
|
||||
}
|
||||
if let f = fonts[key] {
|
||||
return fonts.withLock { fonts in
|
||||
if let f = fonts[key] {
|
||||
return f
|
||||
}
|
||||
let f = ct(size, weight: weight, italic: italic)
|
||||
fonts[key] = f
|
||||
return f
|
||||
}
|
||||
let c = ct(size, weight: weight, italic: italic)
|
||||
let f = (Font(c), c as NSFont)
|
||||
fonts[key] = f
|
||||
return f
|
||||
}
|
||||
|
||||
static func font(_ size: CGFloat, weight: CGFloat = 400, italic: Bool = false) -> Font {
|
||||
cached(size, weight, italic).font
|
||||
Font(cached(size, weight, italic))
|
||||
}
|
||||
|
||||
static func ns(_ size: CGFloat, weight: CGFloat = 400, italic: Bool = false) -> NSFont {
|
||||
cached(size, weight, italic).ns
|
||||
cached(size, weight, italic) as NSFont
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ struct InlineRenderer {
|
||||
private func run(_ s: String, _ style: Style) -> AttributedString {
|
||||
var a = AttributedString(s)
|
||||
a.font = Fonts.font(style.small ? 11 : size, weight: style.bold ? 700 : 400, italic: style.italic)
|
||||
a.appKit.font = Fonts.ns(style.small ? 11 : size, weight: style.bold ? 700 : 400, italic: style.italic)
|
||||
a.mergeAttributes(try! AttributeContainer([.font: Fonts.ns(style.small ? 11 : size, weight: style.bold ? 700 : 400, italic: style.italic)], including: \.appKit))
|
||||
if let link = style.link {
|
||||
a.link = link
|
||||
}
|
||||
@@ -364,7 +364,7 @@ private struct FlowBuilder {
|
||||
s.append(NSAttributedString(string: "\n", attributes: [.font: Fonts.ns(ctx.size)]))
|
||||
let all = NSRange(location: 0, length: s.length)
|
||||
let color = NSColor(ctx.color)
|
||||
s.enumerateAttribute(.foregroundColor, in: all) { value, range, _ in
|
||||
unsafe s.enumerateAttribute(.foregroundColor, in: all) { value, range, _ in
|
||||
if value == nil {
|
||||
s.addAttribute(.foregroundColor, value: color, range: range)
|
||||
}
|
||||
@@ -405,8 +405,8 @@ private struct FlowText: NSViewRepresentable {
|
||||
v.isVerticallyResizable = false
|
||||
v.isHorizontallyResizable = false
|
||||
v.textContainerInset = .zero
|
||||
v.textContainer!.lineFragmentPadding = 0
|
||||
v.textContainer!.widthTracksTextView = true
|
||||
unsafe v.textContainer!.lineFragmentPadding = 0
|
||||
unsafe v.textContainer!.widthTracksTextView = true
|
||||
v.linkTextAttributes = [.cursor: NSCursor.pointingHand]
|
||||
v.delegate = context.coordinator
|
||||
return v
|
||||
@@ -414,11 +414,11 @@ private struct FlowText: NSViewRepresentable {
|
||||
|
||||
func updateNSView(_ v: FlowTextView, context: Context) {
|
||||
context.coordinator.openURL = context.environment.openURL
|
||||
if v.textStorage!.isEqual(to: text) {
|
||||
if unsafe v.textStorage!.isEqual(to: text) {
|
||||
return
|
||||
}
|
||||
let selected = v.selectedRanges
|
||||
v.textStorage!.setAttributedString(text)
|
||||
unsafe v.textStorage!.setAttributedString(text)
|
||||
if selected.allSatisfy({ NSMaxRange($0.rangeValue) <= text.length }) {
|
||||
v.selectedRanges = selected
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ struct WindowReader: NSViewRepresentable {
|
||||
func makeNSView(context: Context) -> NSView {
|
||||
let view = NSView()
|
||||
DispatchQueue.main.async {
|
||||
if let w = view.window {
|
||||
if let w = unsafe view.window {
|
||||
found(w)
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ struct WindowReader: NSViewRepresentable {
|
||||
|
||||
func updateNSView(_ nsView: NSView, context: Context) {
|
||||
DispatchQueue.main.async {
|
||||
if let w = nsView.window {
|
||||
if let w = unsafe nsView.window {
|
||||
found(w)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ private func bytes(_ n: Int64) -> String {
|
||||
v /= 1024
|
||||
i += 1
|
||||
}
|
||||
return String(format: i == 0 ? "%.0f %@" : "%.1f %@", v, units[i])
|
||||
return "\(v.formatted(.number.precision(.fractionLength(i == 0 ? 0 : 1)).grouping(.never))) \(units[i])"
|
||||
}
|
||||
|
||||
private func resetText(_ unixSeconds: Double) -> String {
|
||||
|
||||
@@ -82,7 +82,7 @@ struct TerminalHost: NSViewRepresentable {
|
||||
context.coordinator.view = t
|
||||
DispatchQueue.main.async {
|
||||
colour(t)
|
||||
t.window?.makeFirstResponder(t)
|
||||
unsafe t.window?.makeFirstResponder(t)
|
||||
context.coordinator.connect()
|
||||
}
|
||||
return t
|
||||
|
||||
Reference in New Issue
Block a user