Skip to content

Consider NSTextView-backed rendering for the content view #11

@cameronsjo

Description

@cameronsjo

Companion to the perf issue I'm filing alongside this one.

The current per-block rendering — Text(AttributedString) inside a ScrollView { VStack { ForEach } } — hits two ceilings on long markdown:

  1. Layout cost scales with block count, not viewport, so big docs freeze on open.
  2. SwiftUI's Text selection is per-view. Cross-block selection doesn't work, and textSelection(.enabled) doesn't get AppKit's auto-scroll-during-drag.

Swapping VStack to LazyVStack (suggested in the perf issue) addresses (1) but worsens (2), since off-screen rows aren't there to be selected.

A different shape worth considering: render the parsed markdown to a single NSAttributedString and host it in an NSTextView wrapped via NSViewRepresentable. The text view handles line layout, lazy display, selection with auto-scroll, find-bar integration, and macOS Services without extra work. Code blocks, tables, mermaid diagrams, math — those can live in a parallel block-level layer, or get baked in as text attachments if you want them inside the selectable run.

Real trade-offs:

  • Bigger refactor, especially for the table/code/mermaid block views.
  • Search highlight gets reimplemented against NSTextView's temporary attribute APIs.
  • ToC scroll-to-heading becomes scroll-to-character-range.

Upside: any document opens instantly, native macOS selection (find, lookup, share, drag), and probably less SwiftUI surface area overall. It's the right primitive for a viewer of long markdown.

Not asking for this on a deadline — just flagging the path. Happy to prototype if you're ever interested.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions