Skip to content

Large markdown files (~10K lines) freeze the UI for a couple seconds on open #10

@cameronsjo

Description

@cameronsjo

Opened a ~900KB markdown file — 11,176 lines, 5,567 inline links, 1,868 ATX headings, basically a long list of bookmarks grouped by domain — and the window is unresponsive for a second or two before scroll wakes up. Theme switches and search keystrokes re-trigger it.

I poked around the source. The hot spot looks like the VStack in MarkdownView.swift around line 127:

ScrollView {
    VStack(alignment: .leading, spacing: 8) {
        ForEach(cachedBlocks) { block in
            blockView(for: block)
        }
    }
}

VStack lays out every child eagerly, so SwiftUI instantiates, measures (Core Text), and positions all 1,800+ blocks before painting the first frame. That's the freeze.

I tried swapping VStack for LazyVStack on a local branch and the open is sub-frame. There's a comment in MarkdownBlock.swift:10–13 showing you already debugged the LazyVStack id-getter hot path and made id a stored property, so the swap is safe now.

One catch worth knowing: textSelection(.enabled) inside a LazyVStack loses auto-scroll-during-drag, because off-screen rows aren't materialized when AppKit goes looking for the next selectable view. So the simple swap fixes the perf but trades away a native macOS interaction. There's probably a deeper fix worth its own issue (NSTextView-backed content view); I'm filing that separately.

Happy to send a PR with the LazyVStack change plus a two-pass scrollTo helper (needed because proxy.scrollTo(id, anchor:) to an unmaterialized item under-shoots on macOS 13) and a 150ms debounce on the search recompute path. Patch is small: +30/−9 lines, one file. Or you might want to take a different angle — say the word.

Repro file is just a long bullet list of [text](url) — date lines. Easy to synthesize, or I can attach the one I hit it with.

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