Skip to content

Address issue #382: Normalize CRLF line endings on file load#398

Merged
schuyler merged 2 commits into
mainfrom
claude/resolve-issue-382-dST73
Apr 22, 2026
Merged

Address issue #382: Normalize CRLF line endings on file load#398
schuyler merged 2 commits into
mainfrom
claude/resolve-issue-382-dST73

Conversation

@schuyler

Copy link
Copy Markdown
Owner

Summary

  • Markdown files created on Windows use CRLF (\r\n) line endings. Hoedown's line-based parser expects LF (\n) and fails to render block elements (headings, paragraphs, lists, code blocks) when it encounters \r\n, producing a blank preview.
  • Added CRLF→LF normalization at three levels of defense: on file load (MPDocument.m), in the Quick Look renderer (MPQuickLookRenderer.m), and as a safety net in MPPreprocessMarkdown (MPRenderer.m) for content arriving via paste or programmatic assignment.
  • The existing MPPreprocessMarkdown regexes that fix Issues Rendering of lists is off if it doesn't have a blank line before it #254 and Fix code block formatting when no blank line before block #36 also match \n only, so normalizing before those patterns is required for CRLF files to benefit from those workarounds.
  • Saving a Windows file from MacDown will write it back with LF endings — standard macOS editor behavior.

Related Issue

Related to #382

Manual Testing Plan

Since a Windows machine is not available, create CRLF test files on macOS using Python:

python3 << 'EOF'
import os
test_dir = os.path.expanduser("~/Desktop/MacDown_CRLF_Tests")
os.makedirs(test_dir, exist_ok=True)

# Basic heading + paragraph
open(f"{test_dir}/basic.md", "wb").write(b"# Heading\r\n\r\nParagraph.\r\n")
# List after paragraph (Issue #254 regression check)
open(f"{test_dir}/list.md", "wb").write(b"Paragraph\r\n- Item 1\r\n- Item 2\r\n")
# Fenced code after text (Issue #36 regression check)
open(f"{test_dir}/code.md", "wb").write(b"Text\r\n```python\r\nprint('hi')\r\n```\r\n")
print("Files created in:", test_dir)
EOF

Scenarios:

Review Notes

  • reloadFromDisk requires no change — it calls through to readFromData:ofType:error: and inherits the fix automatically.
  • NSString+Lookup.m front matter CRLF handling is left unchanged; the defensive [\r\n]+ patterns are harmless and provide a useful backstop.
  • Bare \r (legacy Mac OS 9 line endings, obsolete since 2001) is not handled; the risk was judged negligible.

claude added 2 commits April 22, 2026 05:57
Windows-created files use CRLF (\r\n) line endings. Hoedown's line-based
parser expects LF (\n) and fails to render headings, paragraphs, and other
block elements when encountering \r\n, producing blank output for Windows
files while Mac files render correctly.

Fix applied at three levels of defense:
- readFromData:ofType:error: (MPDocument.m): strips \r\n at load time so
  the editor and all downstream code see LF-only content; saving a Windows
  file will write back LF (standard Mac editor behavior)
- renderMarkdownFromURL:error: (MPQuickLookRenderer.m): same normalization
  for the Quick Look path, which loads files independently
- MPPreprocessMarkdown (MPRenderer.m): safety-net strip before Hoedown for
  content arriving via paste or programmatic assignment

Tests added for basic CRLF rendering, list-after-paragraph (Issue #254)
and fenced-code-after-text (Issue #36) workarounds with CRLF, Quick Look
CRLF rendering, and document load API coverage.

Related to #382
@github-actions

github-actions Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Report

Current Coverage: 60.48%

Coverage Details (Summary)
Name                                                                                                                                   Coverage            
-------------------------------------------------------------------------------------------------------------------------------------- ------------------- 
MASPreferences.bundle                                                                                                                  0.00% (0/0)         
MacDown 3000.app                                                                                                                       62.07% (8721/14051) 
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Utility/MPMathJaxListener.m                                                61.54% (16/26)      
        -[MPMathJaxListener callbacks]                                                                                                 100.00% (5/5)       
        -[MPMathJaxListener addCallback:forKey:]                                                                                       100.00% (3/3)       
        -[MPMathJaxListener invokeCallbackForKey:]                                                                                     100.00% (8/8)       
        +[MPMathJaxListener isSelectorExcludedFromWebScript:]                                                                          0.00% (0/5)         
        +[MPMathJaxListener isKeyExcludedFromWebScript:]                                                                               0.00% (0/5)         
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Document/MPAsset.m                                                         93.69% (104/111)    
        -[MPAsset typeName]                                                                                                            100.00% (3/3)       
        -[MPAsset defaultTypeName]                                                                                                     100.00% (3/3)       
        +[MPAsset assetWithURL:andType:]                                                                                               100.00% (3/3)       
        -[MPAsset initWithURL:andType:]                                                                                                87.50% (7/8)        
        -[MPAsset init]                                                                                                                100.00% (3/3)       
        -[MPAsset templateForOption:]                                                                                                  0.00% (0/6)         
        -[MPAsset htmlForOption:]                                                                                                      100.00% (28/28)     
        -[MPStyleSheet defaultTypeName]                                                                                                100.00% (3/3)       
        +[MPStyleSheet CSSWithURL:]                                                                                                    100.00% (3/3)       
        -[MPStyleSheet templateForOption:]                                                                                             100.00% (20/20)     
        -[MPScript defaultTypeName]                                                                                                    100.00% (3/3)       
        +[MPScript javaScriptWithURL:]                                                                                                 100.00% (3/3)       
        -[MPScript templateForOption:]                                                                                                 100.00% (20/20)     
        -[MPEmbeddedScript htmlForOption:]                                                                                             100.00% (5/5)       
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Utility/FileURLInlining.m                                                  26.60% (25/94)      
        +[FileURLInlining inlineFromIterable:]                                                                                         0.00% (0/11)        
        -[FileURLInlining initWithURL:]                                                                                                0.00% (0/6)         
        -[FileURLInlining init]                                                                                                        100.00% (3/3)       
        -[FileURLInlining inlineContent]                                                                                               0.00% (0/9)         
        -[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/Utility/MPResourceWatcherSet.m                                             93.62% (88/94)      
        -[MPResourceWatcherSet init]                                                                                                   100.00% (6/6)       
        -[MPResourceWatcherSet dealloc]                                                                                                0.00% (0/3)         
        -[MPResourceWatcherSet watchedPaths]                                                                                           100.00% (3/3)       
        -[MPResourceWatcherSet updateWatchedPaths:]                                                                                    100.00% (16/16)     
        -[MPResourceWatcherSet addWatcherForPath:]                                                                                     100.00% (32/32)     
        __42-[MPResourceWatcherSet addWatcherForPath:]_block_invoke                                                                    100.00% (6/6)       
        __42-[MPResourceWatcherSet addWatcherForPath:]_block_invoke.5                                                                  93.33% (14/15)      
        __42-[MPResourceWatcherSet addWatcherForPath:]_block_invoke_2                                                                  75.00% (6/8)        
        -[MPResourceWatcherSet stopAll]                                                                                                100.00% (5/5)       
    /Users/runner/work/macdown3000/macdown3000/MacDown/Code/Extension/hoedown_html_patch.c                                             86.47% (115/133)    

... (3167 more lines truncated)

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

@schuyler schuyler merged commit 96db3c4 into main Apr 22, 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