Cherry Markdown Writer

repository·dev·Indexed 26 days ago

https://github.com/tencent/cherry-markdown

A lightweight, extensible JavaScript-based Markdown editor for browser and Node.js environments. It features optimized streaming rendering for AI chat, a VSCode extension, and a specialized @cherry-markdown/miniprogram package for WeChat MiniPrograms. Key capabilities include multi-cursor editing, VIM mode, Mermaid diagrams, math formulas, and support for CommonMark and GFM.

Tokens
7.6K
Snippets
13
Records
43
Agent score
88%

What's inside cherry-markdown

  1. Overview of Cherry Markdown Writer features

    dev

    Cherry Markdown Writer is a lightweight, extensible JavaScript Markdown editor that runs in the browser or on a server via Node.js.

    Key Capabilities:

    • Out-of-the-box: Supports common Markdown syntax (headings, TOC, flowcharts, formulas) immediately upon instantiation.
    • Streaming rendering: Optimized for AI Chat scenarios by auto-completing unfinished Markdown fragments during token streaming.
    • Rich Editing: Includes multi-cursor editing, floating/bubble toolbars, floating TOC, VIM mode, and shortcut customization.
    • Diagrams & Media: Supports Mermaid diagrams (with drag-to-resize), math formulas, table-to-chart, and image/audio/video embedding.
    • Interoperability: Supports pasting from rich text as Markdown and exporting to Image or PDF.
    • Extensibility: Pure JavaScript implementation with no framework dependencies; supports custom syntax, toolbar buttons, and themes.
  2. Overview of Cherry Markdown VSCode Extension

    dev
    The Cherry Markdown VSCode Extension provides an open-source, lightweight, and extensible Markdown editing experience within VSCode. It supports the CommonMark specification, GitHub Flavored Markdown (GFM), and various custom grammars. It is designed for high performance through partial rendering and partial updates.
  3. Install the Cherry Markdown VSCode Extension

    dev

    If you want to use Cherry Markdown directly within Visual Studio Code, you can install the official extension from the VSCode Marketplace. This provides the same rich editing and preview experience as the web version.

    https://marketplace.visualstudio.com/items?itemName=cherryMarkdownPublisher.cherry-markdown
  4. Use CherryStream for streaming Markdown rendering

    dev

    The @cherry-markdown/miniprogram package exports the CherryStream class. It converts Markdown into structured, WXML-friendly data (blocks and runs) instead of updating a DOM.

    Key behaviors:

    • setMarkdown(markdown, options): Accepts the full accumulated Markdown string. It re-renders the entire content to ensure unclosed syntax is handled correctly.
    • Streaming Optimization: During streaming, use { deferImages: true } to render image placeholders. Once the stream is complete, call setMarkdown again with { deferImages: false } to render the actual images.
    • Performance: For high-frequency model output, the application layer should throttle setData updates (e.g., once every 50-100ms) rather than calling it for every chunk.
    • Responsibility: The package does NOT handle SSE requests, byte decoding, framing, or JSON protocols; the application must manage the data stream and pass the accumulated string to CherryStream.
    import CherryStream from '@cherry-markdown/miniprogram';
    
    const page = this;
    const cherry = new CherryStream();
    let markdownContent = '';
    
    function render(streaming) {
      page.setData({
        blocks: cherry.setMarkdown(markdownContent, { deferImages: !streaming }),
        streaming,
      });
    }
    
    function finishStream() {
      render(false);
    }
    
    // Business-side SSE client extracts Markdown string and calls this:
    function onMarkdownChunk(chunk) {
      markdownContent += chunk;
      render(true);
    }
    
    function onStreamComplete() {
      finishStream();
    }
  5. Install @cherry-markdown/miniprogram

    dev

    Install the package via npm to use Cherry Markdown in your WeChat Mini Program. Note that this package provides ESM and requires your application source code to be built into a Mini Program runtime format (e.g., using Rollup) because Mini Programs cannot execute ESM directly.

    npm install @cherry-markdown/miniprogram
  6. Use CherryStream for stream rendering in MiniProgram

    dev

    The @cherry-markdown/miniprogram package exposes CherryStream, which converts Markdown into structured, WXML-friendly view data.

    Implementation Details

    • Input: Use setMarkdown(markdownContent, options) to pass the accumulated Markdown string.
    • Streaming: While a stream is active, pass { deferImages: true } to render image placeholders. When the stream completes, call setMarkdown once with { deferImages: false } to render actual images.
    • Performance: For high-frequency model output, batch your setData calls (e.g., every 50-100 ms) instead of updating on every single chunk.
    • Responsibility: The package does not handle SSE requests, decoding, framing, or payload extraction. You must implement your own transport layer.
    • Rendering: The package returns data blocks; you must provide your own WXML templates, styles, and interaction handlers (like link taps) to render these blocks.
    import CherryStream from '@cherry-markdown/miniprogram';
    
    const page = this;
    const cherry = new CherryStream();
    let markdownContent = '';
    
    function render(streaming) {
      page.setData({
        blocks: cherry.setMarkdown(markdownContent, { deferImages: !streaming }),
        streaming,
      });
    }
    
    function finishStream() {
      render(false);
    }
    
    // Your SSE client extracts Markdown strings from the transport.
    function onMarkdownChunk(chunk) {
      markdownContent += chunk;
      render(true);
    }
    
    function onStreamComplete() {
      finishStream();
    }
  7. Install cherry-markdown via npm or yarn

    dev

    You can install the cherry-markdown package using either npm or yarn to integrate the editor into your project.

    Using npm

    npm install cherry-markdown --save

    Using yarn

    yarn add cherry-markdown

    Note that Cherry provides multiple build artifacts (Full, Core, Stream, and Engine) to support different environments like browsers, Node.js, and AI Chat streaming scenarios. Refer to the Build Artifacts Guide for details on choosing the right bundle.

  8. Configure GFM Unicode Emoji mapping

    dev

    The gfmUnicode configuration object defines how GitHub Flavored Markdown (GFM) emoji shortcodes are mapped to Unicode codepoints and how their corresponding images are retrieved.

    It contains:

    • defaultURL: A template string used to fetch emoji images. It uses the ${code} placeholder to inject the Unicode codepoint.
    • emojis: A mapping of emoji shortcodes (e.g., +1, apple, angry) to their specific Unicode codepoints (e.g., 1f44d, 1f34e, 1f620).
    export const gfmUnicode = {
      defaultURL: 'https://github.githubassets.com/images/icons/emoji/unicode/${code}.png?v8',
      emojis: {
        '+1': '1f44d',
        '-1': '1f44e',
        // ... other emoji mappings
      }
    };
  9. Configure the Editor Behavior

    dev

    The editor object defines the user interface and interaction model of the editor.

    • defaultModel: Sets the initial view mode: 'edit&preview' (split), 'editOnly' (editor only), or 'previewOnly' (preview only).
    • keyMap: Sets the keyboard shortcut style ('sublime' or 'vim').
    • writingStyle: Sets the writing mode: 'normal', 'typewriter', or 'focus'.
    • convertWhenPaste: If true, automatically converts pasted HTML to Markdown.
    • suggester: Configures the autocomplete/suggestion system. You can:
      • Replace the system list via systemSuggestList.
      • Append to it via extendSystemSuggestList.
      • Define custom triggers (e.g., @user, $variable) via the suggester array using keyword and suggestList functions.
    editor: {
      defaultModel: 'edit&preview',
      keyMap: 'sublime',
      writingStyle: 'typewriter',
      suggester: [
        {
          keyword: '@',
          suggestList(word, callback) {
            // Custom logic for @mentions
            callback([{ label: 'User A', value: '@User A ', icon: 'user' }]);
          }
        }
      ]
    }