Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@
--wraptypealiases preserve
--xcodeindentation disabled
--yodaswap always
--disable unusedArguments
--disable unusedArguments,simplifyGenericConstraints
107 changes: 107 additions & 0 deletions Sources/OpenSwiftUICore/View/Text/Text/Text+Image.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//
// Text+Image.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete
// ID: A6FE71E8A6E76FC7E51CBB0D97E0D052 (SwiftUICore)

// MARK: - Text + Image

@available(OpenSwiftUI_v2_0, *)
extension Text {
/// Creates an instance that wraps an `Image`, suitable for concatenating
/// with other `Text`
@available(OpenSwiftUI_v2_0, *)
public init(_ image: Image) {
self.init(anyTextStorage: AttachmentTextStorage(image: image))
}
}

// MARK: - LocalizedStringKey.StringInterpolation + Image

@available(OpenSwiftUI_v2_0, *)
extension LocalizedStringKey.StringInterpolation {
/// Appends an image to a string interpolation.
///
/// Don't call this method directly; it's used by the compiler when
/// interpreting string interpolations.
///
/// - Parameter image: The image to append.
@_semantics("openswiftui.localized.appendInterpolation_@_specifier")
@_semantics("swiftui.localized.appendInterpolation_@_specifier")
public mutating func appendInterpolation(_ image: Image) {
appendInterpolation(Text(image))
}
}

// MARK: - AttachmentTextStorage

final private class AttachmentTextStorage: AnyTextStorage, @unchecked Sendable {
let image: Image

init(image: Image) {
self.image = image
}

override func resolve<T>(
into result: inout T,
in environment: EnvironmentValues,
with options: Text.ResolveOptions
) where T: ResolvedTextContainer {
let context = ImageResolutionContext(
environment: environment,
textStyle: result.style
)
guard resolveAndWriteAuxiliaryMetadataIfNeeded(
into: &result,
context: context,
environment: environment,
options: options
) else {
result.append(
image.resolve(in: context),
in: environment,
with: options
)
return
}
}

override func resolvesToEmpty(
in environment: EnvironmentValues,
with options: Text.ResolveOptions
) -> Bool {
false
}

override func isEqual(to other: AnyTextStorage) -> Bool {
guard let other = other as? AttachmentTextStorage else {
return false
}
return image == other.image
}

override func isStyled(options: Text.ResolveOptions) -> Bool {
true
}

func resolveAndWriteAuxiliaryMetadataIfNeeded<T>(
into result: inout T,
context: ImageResolutionContext,
environment: EnvironmentValues,
options: Text.ResolveOptions
) -> Bool where T: ResolvedTextContainer {
guard options.contains(.writeAuxiliaryMetadata),
let image = image.resolveNamedImage(in: context)

@augmentcode augmentcode Bot Jul 19, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sources/OpenSwiftUICore/View/Text/Text/Text+Image.swift:L96: image.resolveNamedImage(in:) internally calls resolve(in:); when it returns nil (e.g., missing named asset) the fallback path resolves again, which can duplicate the external warning log and do the resolution work twice on the error path.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

else {
return false
}
result.append(
image,
in: environment,
with: options
)
return true
}
}
29 changes: 29 additions & 0 deletions Tests/OpenSwiftUICoreTests/View/Text/TextImageTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// TextImageTests.swift
// OpenSwiftUICoreTests

import OpenSwiftUICore
import Testing

struct TextImageTests {
@Test
func attachmentParticipatesInEquality() {
#expect(Text(Image(systemName: "star")) == Text(Image(systemName: "star")))
#expect(Text(Image(systemName: "star")) != Text(Image(systemName: "circle")))
}

@Test
func attachmentResolvesToObjectReplacementCharacter() {
let text = Text(Image.redacted)

#expect(text.resolveString(in: EnvironmentValues()) == "\u{fffc}")
}

@Test
func imageInterpolationUsesAttachmentText() {
let key: LocalizedStringKey = "Symbol: \(Image.redacted)"
let text = Text(key)

#expect(text.resolveString(in: EnvironmentValues()) == "Symbol: \u{fffc}")
}
}
Loading