Tags: cdpath/SwiftStreamingMarkdown
Tags
Document image support; add Images demo and snapshot test (microsoft#146 ) * Document image support; add Images demo and snapshot test Finalize block-level image support (parts 1-4 already shipped) with the non-rendering deliverables: - README: move Images into the supported list with an accurate description of the experimental ImageConfig source types and fullscreen viewer. - Sample app: add an Images demonstration (enum case, subtitle, fixture) showcasing asset-catalog, bundled-resource, and remote sources, plus image-alongside-text splitting and an unresolved-source placeholder. - Tests: add ImageBlockSnapshotTests rendering a deterministic bundled image via Image(mdImage:); bundle test resources via Package.swift and record the iOS reference snapshots. Refs microsoft#89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Add MarkdownListener bundled-resource fallback; address review Addresses review comments on the image-support PR: - Add `MarkdownListener.resolveBundledResource(fileName:ext:)` (default returns nil). The renderer now resolves bundled-resource images from the app's main bundle first and falls back to the listener when absent, so consumers can serve images that live in a dependency package or framework bundle rather than the app target. Threaded through BundledResourceImage, the fullscreen viewer, and the image-tap payload. - README: move Images up under Paragraphs in the supported list. - Tests: parse Markdown containing a bundled image and verify end-to-end resolution via the listener (the resource lives only in the test bundle); cover the no-listener case; render the image deterministically via Image(mdImage:) for the visual snapshot. Replace the helper's fatalError with throwing XCTUnwrap so a missing resource is a normal test failure. Refs microsoft#89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Snapshot the image failure case; make image controller non-optional Addresses the second review round on PR microsoft#146: - Replace the bundled-image snapshot with the deterministic failure case: a remote image whose host is not in the allowed domains resolves to nil and renders BlockImageFailureView synchronously. The remote and bundled loading paths render asynchronously via `.task`, which the synchronous snapshot harness captures as the loading placeholder, so they can't be snapshotted deterministically. - Remove the direct Image(mdImage:) snapshot and the bundled-resource pipeline-logic tests from the snapshot file; move listener-fallback resolution coverage into ImageTapTests as a fast unit test. - Make ImageData.makeMarkdownImage(controller:) take a non-optional MarkdownController (the default only existed for test convenience); unwrap the environment controller in BlockImageView before building the payload. Refs microsoft#89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Add macOS snapshot references for the image failure test Recorded via the Record macOS Snapshots workflow (runs/29458940981) so the macOS SPM CI job has references for the new failure-placeholder snapshot. Refs microsoft#89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Surround snapshot image with text; keep image controller optional Addresses the latest review comments on PR microsoft#146: - Snapshot: the failure-placeholder test now parses a paragraph before and after the image, so the rendered DocumentView shows text/image/text. - Revert makeMarkdownImage(controller:) to an optional MarkdownController. SwiftUI's environment injection does not guarantee a non-nil controller, so BlockImageView optionally chains onImageTap rather than guarding out. Refs microsoft#89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 * Re-record macOS snapshot references for the text-wrapped image test Regenerated via the Record macOS Snapshots workflow (runs/29460803999) after surrounding the snapshot image with text. Refs microsoft#89 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 17e2748f-66c1-4deb-b557-df65a17c84f5 --------- Co-authored-by: Jun Yan <yanjun@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixed ambiguous Document type on Xcode 27 (microsoft#137) New SwiftUI introduces a Document type which causes conflicts. https://developer.apple.com/documentation/swiftui/document
Fix macOS crash when rendering markdown links (microsoft#130) * Fix macOS crash when rendering markdown links Link.convert stored an empty Swift array as the .underlineStyle attribute value: in a [NSAttributedString.Key: Any] context the [] literal infers as an empty array, not NSUnderlineStyle. TextKit expects an NSNumber there and AppKit calls -integerValue on it during layout, crashing NSTextView with -[Swift.__EmptyArrayStorage integerValue]. UIKit tolerates the bad value, which is why iOS never crashed. Store NSUnderlineStyle([]).rawValue instead and add a regression test asserting the attribute bridges to NSNumber. Fixes microsoft#128 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add attribute type-safety audit test Walks every attribute the conversion pipeline emits across paragraphs, lists, and tables (bold, strikethrough, links, inline code, LaTeX, citations, task lists) and asserts the value types TextKit expects: NSNumber for numeric keys, platform color/font for styling keys, URL, NSTextAttachment, and NSParagraphStyle. Fails on any platform when a wrongly-typed attribute enters the pipeline, so the crash class fixed in the previous commit cannot silently return through another key. Refs microsoft#128 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Update macOS snapshots from CI runner (macOS 26.4) (microsoft#116) Replace locally-recorded macOS snapshots with those generated on the CI runner to ensure pixel-perfect match during CI validation. Recorded via the Record macOS Snapshots workflow on macos-26 runner. Co-authored-by: Jun Yan <yanjun@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore sample streaming demo controls (microsoft#80) * Restore sample streaming demo controls Adds the sample app streaming drawer, playback speed controls, performance metrics, theme picker, and simulator destination selection improvements for local demo builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tighten drawer reveal scroll threshold Only auto-scroll completed content when revealing the controls drawer if the scroll view is effectively at the bottom, avoiding jumps after the user scrolls up slightly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update new sample file headers Matches the new SwiftLint file_header pattern from main for the sample streaming demo files added by this branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address streaming demo review feedback Derive the preferred simulator runtime from the active iPhoneSimulator SDK and preserve simulated stream delay while playback is paused. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Consolidate sample playback, metrics, and streamed source into DemonstrationViewModel - Merge StreamingPlaybackController + StreamingPerformanceModel + TextSimulatedStreamSource into a single @mainactor DemonstrationViewModel that conforms to StreamedMarkdownSource. - Switch scroll-bottom detection to iOS 18's .onScrollGeometryChange (drops the GeometryReader + PreferenceKey + coordinate-space plumbing). - Rewrite waitUntilPlaying() as an event-driven for-await over $isPlaying.values instead of a 75ms busy-poll. - Replace the fastForwardRequest version counter with a Bool flag (isFastForwarding) reset in the existing reset() chokepoint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Move drawer + scroll-bottom UI state onto DemonstrationViewModel Pull isAtScrollBottom and isControlDrawerPresented out of DemonstrationView's local @State and onto the shared viewmodel as @published properties. Drops the @binding chain that threaded isPresented through StreamingControlDrawerView and StreamingControlPanelView; both views now read/write viewModel.isControlDrawerPresented directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Mahyar (Mac) McDonald <252041286+mamcdonald_microsoft@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jun Yan <junyan.cpp@gmail.com>