kyle-n / HighlightedTextEditor

A SwiftUI view for dynamically highlighting user input
MIT License
726 stars 69 forks source link

AppKit Editor Resets Scroll Position When Window Goes Into Background #62

Closed dbarsamian closed 9 months ago

dbarsamian commented 2 years ago

Describe the bug When a window containing HighlightedTextEditor enters the background, the editor scrolls back to the top of the document.

To Reproduce Steps to reproduce the behavior:

  1. In a SwiftUI app targeting the Mac, create a view with a HighlightedTextEditor and run it. Add enough text to make the editor scrollable.
  2. Scroll down any amount.
  3. Make the window enter the background by either clicking outside of the window or pressing Command + Tab to switch apps.
  4. See the editor scroll back to the top.

Expected behavior I expect the HighlightedTextEditor to maintain its scrolled position when its window enters the background.

Screenshots Due to the size of the video, please see this link to watch a demonstration of the bug (https://youtu.be/e_i5UxY-MA8). Note that I attempt to scroll using the mouse as well as the mouse wheel. I also try clicking outside the window as well as Command + Tab out the window.

Environment Please include:

Please let me know if I can provide anything else that would be helpful in tracking down the cause of this bug.

kyle-n commented 2 years ago

@dbarsamian Hmmmm. The bug is very clear in your video but I'm still figuring out how to reproduce it on my end. I followed the steps and did not see the jump to top. I'm on:

I have an old laptop I can upgrade to macOS 12.3, to see if that's the issue.

Could you also post the SwiftUI view containing your HLTE instance? There may be some odd interaction going on with the container.

dbarsamian commented 2 years ago

@kyle-n Sorry, I had forgotten to include that context. Here's some screenshots of the code containing the HLTE instance. I have a HSplitView/VSplitView that contains editorContent, which has the HLTE instance, in addition to another view.

Edit: I just tested this same layout but with HStack/VStack replacing the Split Views and am not experiencing the issue. It seems to be some interaction with the Split Views and HLTE causing this bug.

Screen Shot 2022-03-31 at 10 12 17 AM image
dbarsamian commented 2 years ago

I've done some more digging on this and it seems that the behavior is caused by the view being constantly redrawn when the window goes into the background and foreground, as well as if the view layout changes at all. Specifically this section of code in HighlightedTextEditor.AppKit.swift gets called every time updateNSView gets called:

image

I attempted to move this snippet to the init of ScrollableTextView and that seemed to fix it, though I'm unsure if this would be an actual solution to this. Some other buggy behavior I've come across with in SwiftUI's H/VStackViews cause other problems that lead me to believe it's an issue with SwiftUI and not your view.

kyle-n commented 2 years ago

I've been looking into this problem and am still working on reproducing this issue. Here's the sample code I've tried:

struct ContentView: View {

    @State private var text: String = """
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a

    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    a
    scroll down here
    """

    var body: some View {
        GeometryReader { geo in
            Group {
                if geo.size.width > 900 {
                    HSplitView {
                        editorContent()
                    }
                } else {
                    VSplitView {
                        editorContent()
                    }
                }
            }
        }
    }

    private func editorContent() -> some View {
        HighlightedTextEditor(text: $text, highlightRules: .markdown)
            .frame(minWidth: 450)
            .id("TextEditor")
    }
}

I also set a breakpoint inside ScrollableTextView's viewWillDraw() and it was not called when I switched the application to the background. Looking at the documentation for viewWillDraw(), that seems to make sense?


Also, when posting code on GitHub, be sure to use code blocks and not screenshots. Easier to copy :)