CocoaMarkdown Documentation

repository·master·Indexed 22 days ago

https://github.com/indragiek/cocoamarkdown

A cross-platform framework for parsing and rendering Markdown on iOS and macOS. Built on the CommonMark C reference implementation, it provides tools for efficient NSAttributedString creation via CMAttributedStringRenderer, HTML rendering via CMHTMLRenderer, and AST traversal using CMNode and CMIterator. It includes CMTextAttributes for styling and CMParser for building custom renderers through a delegate API.

Tokens
2K
Snippets
8
Records
8
Agent score
29%

What's inside CocoaMarkdown

  1. Install CocoaMarkdown via Git Submodule

    master

    To integrate CocoaMarkdown into your iOS or macOS project, follow these steps:

    1. Add the repository as a git submodule:
      git submodule add https://github.com/indragiek/CocoaMarkdown.git
    2. Initialize and update the dependencies:
      cd CocoaMarkdown
      git submodule update --init --recursive
    3. Add the framework to your Xcode project:
      • Drag the .xcodeproj file from the CocoaMarkdown directory into your project.
      • In your target's General tab, find the Embedded Binaries section.
      • Click the + button and select CocoaMarkdown.framework.
    git submodule add https://github.com/indragiek/CocoaMarkdown.git
    cd CocoaMarkdown
    git submodule update --init --recursive
  2. Customize List styles

    master

    You can customize list bullets and numbering formats using addParagraphStyleAttributes on a CMTextAttributes instance.

    let textAttributes = CMTextAttributes()
    
    // Customize unordered list bullets
    textAttributes.addParagraphStyleAttributes([ .listItemBulletString: "🍏" ], forElementWithKinds: .unorderedList)
    
    // Customize ordered list numbering format and indentation
    textAttributes.addParagraphStyleAttributes([ .listItemNumberFormat: "(%02ld)", 
                                                 .listItemLabelIndent: 30 ],    
                                               forElementWithKinds: .orderedList)
    textAttributes.addParagraphStyleAttributes([ .listItemBulletString: "🍏" ], 
                                               forElementWithKinds: .unorderedList)
    textAttributes.addParagraphStyleAttributes([ .listItemNumberFormat: "(%02ld)", 
                                                 .listItemLabelIndent: 30 ],    
                                               forElementWithKinds: .orderedList)
  3. Render Markdown to HTML

    master

    If you need an HTML string instead of an attributed string, use CMHTMLRenderer or the CMDocument convenience method.

    Using CMHTMLRenderer

    let document = CMDocument(contentsOfFile: path, options: [])
    let renderer = CMHTMLRenderer(document: document)
    let HTML = renderer.render()

    Using CMDocument convenience method

    let HTML = CMDocument(contentsOfFile: path).HTMLString()
    let document = CMDocument(contentsOfFile: path, options: [])
    let renderer = CMHTMLRenderer(document: document)
    let HTML = renderer.render()
  4. Traverse the Markdown AST

    master

    CocoaMarkdown provides CMNode and CMIterator to wrap CommonMark's C types, allowing you to traverse the Markdown Abstract Syntax Tree (AST) using an object-oriented interface.

    let document = CMDocument(contentsOfFile: path, options: [])
    document.rootNode.iterator().enumerateUsingBlock { (node, _, _) in
        print("String value: \(node.stringValue)")
    }
    let document = CMDocument(contentsOfFile: path, options: [])
    document.rootNode.iterator().enumerateUsingBlock { (node, _, _) in
        print("String value: \(node.stringValue)")
    }
  5. Support HTML elements with Transformers

    master

    You can extend the CMAttributedStringRenderer to support specific HTML tags by registering CMHTMLElementTransformer implementations. The framework provides built-in transformers for common tags like strikethrough, superscript, and subscript.

    let document = CMDocument(contentsOfFile: path, options: [])
    let renderer = CMAttributedStringRenderer(document: document, attributes: CMTextAttributes())
    renderer.registerHTMLElementTransformer(CMHTMLStrikethroughTransformer())
    renderer.registerHTMLElementTransformer(CMHTMLSuperscriptTransformer())
    textView.attributedText = renderer.render()
    let document = CMDocument(contentsOfFile: path, options: [])
    let renderer = CMAttributedStringRenderer(document: document, attributes: CMTextAttributes())
    renderer.registerHTMLElementTransformer(CMHTMLStrikethroughTransformer())
    renderer.registerHTMLElementTransformer(CMHTMLSuperscriptTransformer())
    textView.attributedText = renderer.render()
  6. Build custom renderers with CMParser

    master

    The CMParser class provides an NSXMLParser-style delegate API. This allows you to build your own custom renderers by responding to callbacks as the parser traverses the AST.

    Implement the CMParserDelegate protocol to handle events like document start/end, text discovery, or finding specific elements like horizontal rules (HRule).

    @protocol CMParserDelegate <NSObject>
    @optional
    - (void)parserDidStartDocument:(CMParser *)parser;
    - (void)parserDidEndDocument:(CMParser *)parser;
    - (void)parser:(CMParser *)parser foundText:(NSString *)text;
    - (void)parserFoundHRule:(CMParser *)parser;
    @end
    @protocol CMParserDelegate <NSObject>
    @optional
    - (void)parserDidStartDocument:(CMParser *)parser;
    - (void)parserDidEndDocument:(CMParser *)parser;
    ...
    - (void)parser:(CMParser *)parser foundText:(NSString *)text;
    - (void)parserFoundHRule:(CMParser *)parser;
    ...
    @end
  7. Customize text styling with CMTextAttributes

    master

    Use the CMTextAttributes class to define how different Markdown elements are styled. You can set three types of attributes:

    • String attributes: Standard NSAttributedString attributes.
    • Font attributes: For setting fonts and traits (supports automatic Dynamic-Type compliance on iOS).
    • Paragraph attributes: For block-level styling like alignment or list markers.

    Grouped attribute styling

    Instead of setting attributes for every single node, use grouped methods to apply styles to specific element kinds (e.g., .anyHeader, .blockQuote, .inlineCode).

    let textAttributes = CMTextAttributes()
    
    // Set text color for all headers
    textAttributes.addStringAttributes([ .foregroundColor: UIColor.blue], forElementWithKinds: .anyHeader)
    
    // Set font and traits for headers
    textAttributes.addFontAttributes([ .family: "Avenir Next" ], forElementWithKinds: .anyHeader)
    
    // Set alignment for block quotes
    textAttributes.addParagraphStyleAttributes([ .alignment: NSTextAlignment.center.rawValue], forElementWithKinds: .blockQuote)
    let textAttributes = CMTextAttributes()
    textAttributes.addStringAttributes([ .foregroundColor: UIColor(red: 0.0, green: 0.446, blue: 0.657, alpha: 1.0)], 
                                       forElementWithKinds: .anyHeader)
    
    textAttributes.addFontAttributes([ .family: "Avenir Next" ,
                                       .traits: [ UIFontDescriptor.TraitKey.symbolic: boldItalicTrait.rawValue]], 
                                     forElementWithKinds: .anyHeader)
    
    textAttributes.addParagraphStyleAttributes([ .alignment: NSTextAlignment.center.rawValue], 
                                               forElementWithKinds: .blockQuote)
  8. Render Markdown as NSAttributedString

    master

    The CMAttributedStringRenderer is the high-level API for converting Markdown directly into NSAttributedString objects, which is ideal for native rendering on iOS and macOS without an intermediate HTML step.

    Using CMAttributedStringRenderer

    let document = CMDocument(contentsOfFile: path, options: [])
    let renderer = CMAttributedStringRenderer(document: document, attributes: CMTextAttributes())
    textView.attributedText = renderer.render()

    Using CMDocument convenience method

    textView.attributedText = CMDocument(contentsOfFile: path, options: []).attributedStringWithAttributes(CMTextAttributes())
    let document = CMDocument(contentsOfFile: path, options: [])
    let renderer = CMAttributedStringRenderer(document: document, attributes: CMTextAttributes())
    textView.attributedText = renderer.render()