Skip to content

Fix editor jumping when typing at end of long documents#288

Merged
schuyler merged 3 commits intomainfrom
claude/research-issue-282-3P1Ss
Jan 22, 2026
Merged

Fix editor jumping when typing at end of long documents#288
schuyler merged 3 commits intomainfrom
claude/research-issue-282-3P1Ss

Conversation

@schuyler
Copy link
Copy Markdown
Owner

@schuyler schuyler commented Jan 22, 2026

Summary

Fixes an issue where the editor would jump to the middle of the document when typing at the end of a long document.

Root cause: The editorBoundsDidChange: handler triggered syncScrollers on every keystroke because content height changes. The sync algorithm recalculated scroll position based on header reference points, and as content grew, headers crossed the filtering threshold causing reference points to change and the editor to jump.

Solution: Add an inEditing flag that prevents scroll synchronization during active typing. A delayed sync (200ms) runs after editing pauses, allowing the layout to stabilize before syncing. This follows the existing inLiveScroll pattern.

Changes

  • Add inEditing property to track active editing state
  • Modify editorBoundsDidChange: to skip sync when inEditing is YES
  • Add performDelayedSyncScrollers method for delayed sync after typing pauses
  • Modify editorTextDidChange: to set inEditing and schedule delayed sync
  • Add cleanup in close method to cancel pending delayed sync (prevents crash)
  • Add 8 new tests for editing state behavior
  • Update test coverage documentation

Related Issue

Related to #282

Manual Testing Plan

Key Test Scenarios

  1. Primary Bug Fix - Typing at End of Long Document

    • Open a document with 100+ headers
    • Scroll to the very end and type rapidly
    • Expected: Editor should NOT jump; cursor stays at end; preview syncs after ~200ms pause
  2. Continuous Typing Behavior

    • Type continuously for 5-10 seconds in a long document
    • Expected: No scroll sync during typing; smooth sync after stopping
  3. Document Close During Editing

    • Start typing rapidly, then immediately close (Cmd+W within 200ms)
    • Expected: No crash; document closes cleanly
  4. Live Scroll Still Works

    • Drag the editor scrollbar rapidly
    • Expected: Preview follows editor scroll position normally
  5. Sync Disabled

    • Disable scroll sync in Preferences > Editor
    • Expected: No behavioral changes, no errors

Edge Cases

  • Rapid typing followed by rapid scrolling
  • Copy-paste at document end
  • Find/Replace operations
  • Undo/Redo operations
  • Multiple documents open simultaneously

When typing at the end of a long document, the editor would jump to the
middle of the document because editorBoundsDidChange: triggered
syncScrollers on every keystroke. The sync algorithm recalculated scroll
position based on header reference points, and as content grew, headers
crossed the filtering threshold causing reference points to change.

This fix adds an inEditing flag that prevents scroll synchronization
during active typing. A delayed sync (200ms) runs after editing pauses,
allowing the layout to stabilize before syncing.

Changes:
- Add inEditing property to track editing state
- Modify editorBoundsDidChange: to skip sync when inEditing is YES
- Add performDelayedSyncScrollers method for delayed sync after typing
- Modify editorTextDidChange: to set inEditing and schedule delayed sync
- Add tests for the new editing state behavior

Related to #282
Cancel pending performDelayedSyncScrollers in the close method to prevent
crash if document is closed within 200ms of last keystroke. Without this,
the delayed selector could fire on a deallocated object.

Also adds test for close cleanup behavior.

Related to #282
Update MPScrollSyncTests documentation to include the 8 new tests added
for editing-state-aware scroll sync behavior.

Related to #282
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jan 22, 2026

Code Coverage Report

Current Coverage: 52.80%

Coverage Details (Summary)
Name                                                                                                                                   Coverage            
-------------------------------------------------------------------------------------------------------------------------------------- ------------------- 
MASPreferences.bundle                                                                                                                  0.00% (0/0)         
MacDown 3000.app                                                                                                                       58.99% (7641/12953) 
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Extension/NSColor+HTML.m                                                   94.05% (332/353)    
        +[NSColor(HTML) colorWithHexString:]                                                                                           94.12% (16/17)      
        +[NSColor(HTML) colorWithHTMLName:]                                                                                            89.13% (164/184)    
        __35+[NSColor(HTML) colorWithHTMLName:]_block_invoke                                                                           100.00% (152/152)   
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Document/MPDocument.m                                                      57.00% (1038/1821)  
        MPEditorPreferenceKeyWithValueKey                                                                                              85.71% (6/7)        
        MPEditorKeysToObserve                                                                                                          100.00% (15/15)     
        __MPEditorKeysToObserve_block_invoke                                                                                           100.00% (10/10)     
        MPEditorPreferencesToObserve                                                                                                   100.00% (13/13)     
        __MPEditorPreferencesToObserve_block_invoke                                                                                    100.00% (8/8)       
        MPRectStringForAutosaveName                                                                                                    100.00% (6/6)       
        MPAreNilableStringsEqual                                                                                                       100.00% (3/3)       
        MPGetWebViewBackgroundColor                                                                                                    0.00% (0/9)         
        -[NSURL(Convert) absoluteBaseURLString]                                                                                        0.00% (0/6)         
        -[WebView(Shortcut) enclosingScrollView]                                                                                       100.00% (3/3)       
        -[MPPreferences(Hoedown) extensionFlags]                                                                                       75.00% (21/28)      
        -[MPPreferences(Hoedown) rendererFlags]                                                                                        75.00% (9/12)       
        MPGetPreviewLoadingCompletionHandler                                                                                           100.00% (26/26)     
        __MPGetPreviewLoadingCompletionHandler_block_invoke                                                                            100.00% (23/23)     
        -[MPDocument preferences]                                                                                                      100.00% (3/3)       
        -[MPDocument markdown]                                                                                                         100.00% (3/3)       
        -[MPDocument setMarkdown:]                                                                                                     100.00% (3/3)       
        -[MPDocument html]                                                                                                             0.00% (0/3)         
        -[MPDocument toolbarVisible]                                                                                                   0.00% (0/3)         
        -[MPDocument previewVisible]                                                                                                   100.00% (3/3)       
        -[MPDocument editorVisible]                                                                                                    100.00% (3/3)       
        -[MPDocument needsHtml]                                                                                                        80.00% (4/5)        
        -[MPDocument setTotalWords:]                                                                                                   0.00% (0/7)         
        -[MPDocument setTotalCharacters:]                                                                                              0.00% (0/7)         
        -[MPDocument setTotalCharactersNoSpaces:]                                                                                      0.00% (0/8)         
        -[MPDocument setAutosaveName:]                                                                                                 100.00% (4/4)       
        -[MPDocument init]                                                                                                             90.00% (9/10)       
        -[MPDocument windowNibName]                                                                                                    100.00% (3/3)       
        -[MPDocument windowControllerDidLoadNib:]                                                                                      100.00% (88/88)     
        __41-[MPDocument windowControllerDidLoadNib:]_block_invoke                                                                     100.00% (4/4)       
        -[MPDocument reloadFromLoadedString]                                                                                           100.00% (8/8)       
        -[MPDocument close]                                                                                                            17.39% (4/23)       
        +[MPDocument autosavesInPlace]                                                                                                 100.00% (2/2)       
        +[MPDocument writableTypes]                                                                                                    100.00% (3/3)       
        -[MPDocument isDocumentEdited]                                                                                                 100.00% (5/5)       
        -[MPDocument writeToURL:ofType:error:]                                                                                         0.00% (0/15)        
        -[MPDocument dataOfType:error:]                                                                                                100.00% (3/3)       
        -[MPDocument readFromData:ofType:error:]                                                                                       100.00% (8/8)       
        -[MPDocument prepareSavePanel:]                                                                                                76.92% (30/39)      
        __31-[MPDocument prepareSavePanel:]_block_invoke                                                                               100.00% (12/12)     
        -[MPDocument printInfo]                                                                                                        0.00% (0/12)        

... (2474 more lines truncated)

📊 **Full coverage report available in workflow artifacts**

@schuyler schuyler merged commit 17ee236 into main Jan 22, 2026
10 checks passed
schuyler pushed a commit that referenced this pull request Jan 24, 2026
Comprehensive testing plan covering all changes since v3000.0.3:
- Smart quote substitution fix (#289)
- Editor jumping when typing at end of long documents (#288)
- New document window positioning (#286)
- Graphviz/Mermaid button positioning in Compilation Settings (#280)
- Adjacent shortcut-style links rendering (#275)

Includes regression testing checklist for core functionality.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants