Skip to content

Fix Issue #294: Update word count during DOM replacement#296

Merged
schuyler merged 4 commits into
mainfrom
claude/resolve-issue-294-TZfle
Feb 4, 2026
Merged

Fix Issue #294: Update word count during DOM replacement#296
schuyler merged 4 commits into
mainfrom
claude/resolve-issue-294-TZfle

Conversation

@schuyler

@schuyler schuyler commented Feb 4, 2026

Copy link
Copy Markdown
Owner

Summary

The word/character count in the status bar was not updating during normal editing because the DOM replacement optimization path (used for most edits) skipped the didFinishLoadForFrame: callback where updateWordCount was called.

Changes:

  • Add scheduleWordCountUpdate method with 300ms debouncing using NSBlockOperation
  • Add wordCountUpdateQueue NSOperationQueue for managing debounced updates
  • Add proper cancellation check with isCancelled after sleep delay
  • Call scheduleWordCountUpdate in the DOM replacement path
  • Add cleanup in close method to cancel pending operations
  • Add unit tests in MPWordCountUpdateTests.m

Related Issue

Related to #294

Manual Testing Plan

Prerequisites

  1. Build and run MacDown 3000 from this branch
  2. Enable word count display in Preferences > General > "Show word count"
  3. Locate the word count widget in the bottom-left corner of the editor

Test Scenarios

1. Basic Word Count Updates

  • Create a new document and type "Hello world"
  • Word count should update to "2 words" within ~300-500ms after typing stops
  • Add more text and verify count updates

2. Rapid Typing (Debouncing)

  • Type rapidly without pausing
  • Application should remain responsive
  • Word count should update only after a brief pause (~300ms)

3. Editing Operations

  • Test delete, undo, paste operations
  • Verify count updates correctly after each operation

4. Preference Toggle

  • Toggle "Show word count" off and on
  • Verify widget appears/disappears correctly
  • Verify count updates still work after re-enabling

5. Preview Pane Hidden

  • Hide the preview pane
  • Verify word count still updates during editing

Edge Cases

  • Empty document: should show 0 words
  • Whitespace only: should show 0 words
  • Document close during update: should not crash

Review Notes

  • Code review: Fixed race condition in cancellation logic using NSBlockOperation with isCancelled check
  • Debouncing pattern follows existing codebase conventions (similar to MPRenderer's parseAndRenderWithMaxDelay)
  • Thread safety ensured by updating on main thread via dispatch_async

The word count was only updating after full WebView reloads via
didFinishLoadForFrame:, but the DOM replacement optimization path
(used for most edits) skipped this callback entirely.

Changes:
- Add scheduleWordCountUpdate method with debouncing (300ms) to avoid
  performance issues during rapid typing
- Call scheduleWordCountUpdate in the DOM replacement path
- Add wordCountUpdateQueue NSOperationQueue for debouncing
- Cancel pending updates on document close to prevent crashes
- Add unit tests for the new functionality

Related to #294

https://claude.ai/code/session_01K3sCpwVKwQZQmndbHxA829
Skip testWordCountUpdateQueueInitializedAfterWindowSetup when running
in headless CI mode where windowControllerDidLoadNib is not called.

Related to #294

https://claude.ai/code/session_01K3sCpwVKwQZQmndbHxA829
- Use NSBlockOperation with isCancelled check after sleep to properly
  cancel pending operations (fixes race condition where cancelled
  operations would still dispatch updateWordCount)
- Add nil check for wordCountUpdateQueue before use
- Add queue name for debugging

Related to #294

https://claude.ai/code/session_01K3sCpwVKwQZQmndbHxA829
Add MPWordCountUpdateTests.m to the test files inventory and update
the partial coverage section to document word count testing.

Related to #294

https://claude.ai/code/session_01K3sCpwVKwQZQmndbHxA829
@github-actions

github-actions Bot commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Report

Current Coverage: 54.11%

Coverage Details (Summary)
Name                                                                                                                                   Coverage            
-------------------------------------------------------------------------------------------------------------------------------------- ------------------- 
MASPreferences.bundle                                                                                                                  0.00% (0/0)         
MacDown 3000.app                                                                                                                       59.76% (7841/13121) 
    /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/Utility/MPMathJaxListener.m                                                0.00% (0/26)        
        -[MPMathJaxListener callbacks]                                                                                                 0.00% (0/5)         
        -[MPMathJaxListener addCallback:forKey:]                                                                                       0.00% (0/3)         
        -[MPMathJaxListener invokeCallbackForKey:]                                                                                     0.00% (0/8)         
        +[MPMathJaxListener isSelectorExcludedFromWebScript:]                                                                          0.00% (0/5)         
        +[MPMathJaxListener isKeyExcludedFromWebScript:]                                                                               0.00% (0/5)         
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Utility/FileURLInlining.m                                                  22.92% (22/96)      
        +[FileURLInlining inlineFromIterable:]                                                                                         0.00% (0/11)        
        +[FileURLInlining withURL:]                                                                                                    0.00% (0/4)         
        -[FileURLInlining inlineContent]                                                                                               0.00% (0/9)         
        -[FileURLInlining initWithURL:]                                                                                                0.00% (0/7)         
        -[FileURLInlining imageContent]                                                                                                0.00% (0/12)        
        +[FileURLInlining mimeTypeForFilePath:]                                                                                        100.00% (22/22)     
        -[FileURLInlining clippingContent]                                                                                             0.00% (0/4)         
        +[FileURLInlining isTextClippingAtPath:]                                                                                       0.00% (0/12)        
        +[FileURLInlining textContentFromClipping:]                                                                                    0.00% (0/15)        
    /Users/runner/work/macdown3000/macdown3000/Dependency/peg-markdown-highlight/HGMarkdownHighlightingStyle.m                         87.69% (57/65)      
        +[HGMarkdownHighlightingStyle colorFromARGBColor:]                                                                             100.00% (6/6)       
        -[HGMarkdownHighlightingStyle initWithType:attributesToAdd:toRemove:fontTraitsToAdd:]                                          88.89% (8/9)        
        -[HGMarkdownHighlightingStyle initWithStyleAttributes:baseFont:]                                                               86.00% (43/50)      
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Extension/hoedown_html_patch.c                                             86.47% (115/133)    
        hoedown_patch_reset_checkbox_index                                                                                             100.00% (3/3)       
        hoedown_patch_get_checkbox_index                                                                                               0.00% (0/3)         
        hoedown_patch_render_blockcode                                                                                                 89.09% (49/55)      
        hoedown_patch_render_listitem                                                                                                  100.00% (44/44)     
        hoedown_patch_render_toc_header                                                                                                67.86% (19/28)      
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Application/MPMainController.m                                             42.91% (106/247)    
        MPOpenBundledFile                                                                                                              96.67% (29/30)      
        __MPOpenBundledFile_block_invoke                                                                                               85.71% (6/7)        
        treat                                                                                                                          20.00% (6/30)       
        __treat_block_invoke                                                                                                           0.00% (0/3)         
        -[MPMainController applicationDidFinishLaunching:]                                                                             100.00% (6/6)       
        -[MPMainController openUrlSchemeAppleEvent:withReplyEvent:]                                                                    0.00% (0/45)        
        __59-[MPMainController openUrlSchemeAppleEvent:withReplyEvent:]_block_invoke                                                   0.00% (0/7)         
        -[MPMainController valueForKey:fromQueryItems:]                                                                                0.00% (0/5)         
        -[MPMainController preferences]                                                                                                100.00% (3/3)       
        -[MPMainController preferencesWindowController]                                                                                0.00% (0/18)        
        -[MPMainController showPreferencesWindow:]                                                                                     0.00% (0/2)         
        -[MPMainController showHelp:]                                                                                                  100.00% (3/3)       
        -[MPMainController showContributing:]                                                                                          100.00% (3/3)       
        -[MPMainController init]                                                                                                       90.91% (10/11)      
        -[MPMainController applicationShouldOpenUntitledFile:]                                                                         80.00% (4/5)        

... (2587 more lines truncated)

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

@schuyler schuyler merged commit 0548896 into main Feb 4, 2026
10 checks passed
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