MultiMarkdown Composer (MMKD-Cmp) and Scrivener Work Together

MMKD-Cmp is designed for more than the individual document creation that most of the minimalistic Markdown based writing applications specialize in. This is an application which lends itself to the production of long form documents with images, tables, footnotes and citations if you so wish. It includes math support, automatic cross-referencing, glossary entries (via LaTeX), and document metadata when you need it. With a detailed system of preferences, support for MathJax and CriticMarkup, text completions, and keybindings, Composer hits the sweet spot. The only competitor who might challenge Composer is Typora.

MMKD-Cmp Advantages Over iA-Writer

Note: IA Writer is a MacOS/iOS distraction-free writing app

  1. Composer deals with multiple open files. Thanks to its support of the system tabs feature, I can have multiple documents open in tabs in a single window. Reduces clutter and makes it possible to have multiple documents easily accessible.
  2. Composer supports CriticMarkup.
  3. Composer supports Table of Contents (TOC) in its sidebar. This makes navigation simpler for large documents. Makes it possible to change the order of sections in documents by dragging and dropping sections into the desired order.
  4. Typewriter scrolling can be set for the spot you desire.
  5. Composer keybindings let you make changes to existing keyboard commands and add your own keyboard commands.
  6. Theme support makes available other options beyond dark and white.

MMKD-Cmp Table of Contents Sidebar

MMKD-Cmp generates a Table of Contents (TOC) sidebar from the headings in your document. Clicking on a heading takes you to that section in your document. You can search/filter based on content of the heading. Most importantly, you can drag and drop headings in the TOC sidebar to rearrange your document. Reminds me of Scrivenerand its Binder.

Scrivener is an accessible tool for anyone doing serious content creation. It lets you focus on developing the content, then worry about appearance and formatting during the final compile phase.

Scrivener is part of my Markdown toolchain. I iteratively write in Scrivener and preview in MultiMarkdown Composer.

Is it perfect? No. I wish native nested lists compiled to Markdown, but the Preserve Formatting feature is a great workaround that provides support for coding Markdown tags directly in the content.

In WordPress blogs, if you have JetPack plugin active you can tick a box for using markup language during writing posts.

Follow these steps to configure the Compile dialog for Markdown output.

  • Set the Compile For pull down menu to MultiMarkdown.
  • In the Format table, select Basic MultiMarkdown.
  • Open the Assign Section Layout dialog.
    • In the Assign Section Layout dialog, select both Heading and Section from the section type list and assign them to the template called Text Section With Heading. This tells Scrivener to use the binder titles of folder and documents as Markdown headings.
    • Press Enter to close the Assign Section Layout dialog.
  • Back in the Compile dialog, select the Option tab. Check the following checkboxes:
    • Convert Rich Text to MultiMarkdown
    • Treat “Preserve Formatting” as Raw Markup.
  • Press Enter to close the Compile dialog and generate output.

Links just work. Use Scrivener’s native link support. Here are the steps.

  1. Copy the target link to the pasteboard (from the browser address bar).
  2. In Scrivener, select the text to associate with the link.
  3. Open the Edit menu and select Add Link.
  4. The Add Link dialog populates the address field using the link from your pasteboard. Then hit Enter.

When you compile to Markdown, the document text from step 2 will appear in brackets, followed by the target link address in parenthesis. The text from step 2 appears as a clickable link in MultiMarkdown Composer.


Scrivener’s native Table support produces the appropriate Markdown. Select Table from the Insert menu. The default table has two rows and three columns. Use the Table submenu from the Format menu to modify the table. Markdown output uses the first row as column headers.

Here’s an example table using Scrivener’s native table format.

| Name | Age | | :—– | :—– | | Fred | 19 | | Andrea | 38 | | Larry | 62 |

Creating Headings

Probably the single best reason to not hand-code Markdown is that changes to heading level must be done manually, and it’s a real pain. Scrivener has a better solution — use Scrivener document and folder titles in the binder.

If your binder titles aren’t showing up as headings in the Markdown output, take a look at how you’ve set up section layouts. In the Compile dialog, open the Assign Section Layouts dialog and make sure that Heading and Section are set to Text Section With Heading, as described previously. Once you’ve done this, the folder and document titles in the binder compile to Markdown headings and the folder and document text compile to body text following the headings.

  • The name of a folder becomes a Heading 1, and the
  • The name of a document in the folder becomes a Heading 2
  • Nest the folders to create subsections within sections.

Scrivener lets you embed Markdown and HTML tags directly in your content.

For any raw html entered into Scrivener (except HTML entities) . . . Format->Preserve Formatting

**** for horizontal rule

— for horizontal rule

— and – just work


For indented lists, . . . Format->Preserve Formatting

For simple lists, one can use Scrivener’s native list mechanism. Go to the Format menu, open the List submenu, and select the desired list type.

This document shares how I work with Markdown inside of Scrivener. The goal is to use the best features of Markdown and Scrivener to get a smooth combined work flow.

Scrivener supports Markdown in that it allows you to easily structure your document with chapters and sections while letting you to use Markdown (actually MultiMarkdown) to format your document. Once you’ve written your sections using Markdown syntax, you compile the document for MultiMarkdown output by choosing the “Multimarkdown” option in the compile dialog box.

Scrivener does this compilation by rendering the structural contents in the binder as MultiMarkdown headers and subheaders Chapters become #Chapter and sections become ##Sections## based upon the folder’s level in the document.


If you paste an image into Scrivener (as is done above) then the Multimarkdown compiler creates a directory that contains your Markdown document and the image. The Markdown document references the image in the folder and so you see it in any Markdown viewer.

You can add a caption to an image by putting the caption between square brackets [] on the next line.

Work Flow

Markdown (and, of course it’s descendent MultiMarkdown) is a fantastic tool for those of us who want to use formatting in our documents, but who hate reaching for the mouse. Also, Markdown documents can become anything we need: web pages, Word documents, or PDF (such as this one.)

Scrivener does an excellent job of translating structure and images into a Markdown document. I think it’s best to use Scrivener for this function and to use other tools for downstream steps. My Scrivener/Markdown flow looks like this:

  1. Create a Scrivener project and structure the chapters and scenes as I like.
  2. Write your documents using Markdown syntax to impart format information.1
  3. Compile the project for MulitMarkdown, ignoring the options to create RTF or LaTeX directly from my project. See the image above.
  4. Use your favorite Markdown renderer to create the downstream formats you want.2
  5. This footnote was created using Markdown format.↩
  6. I like Marked 2 on the Mac. This footnote was created using Scrivener’s Insert -> Footnote command. It creates the correct Markdown format.

Scrivener and Marked

For those authors who primarily use the software to compose in a Markdown dialect, HTML, LaTeX, or any of the other common markup syntax systems, emulating a plain-text appearance can prove beneficial. The default settings in Scrivener assume one has a word processing intent in mind. They uses a carefully typeset layout that mimics common end-production feel with indentation of paragraphs and a classic proportional serif font, Palatino. As nice as this looks, it can be deceiving to use indents and paragraph spacing when you need to be aware of such things as literal whitespace characters in your document.

I’ve put together a preference file (compatible with Scrivener 3x for Mac, and 1x Windows) which changes a few of the defaults to better suit a plain-text driven authoring environment. If you have already made considerable modification to your settings, it may be counterproductive to overwrite them all with this basic set; thus the following itemises the changes so that you can make them individually as you see fit:

The preferences below use the Inconsolata font which has been included in the zip file. You should install this font first, and restart Scrivener, before using the preferences file.

  • All pseudo-spacing at the paragraph level has been disabled.
  • There will be no first-line indents or extra spaces following a carriage return.
  • Tab stops are set to every 29pts, which closely emulates four spaces.
  • All typographic substitutions have been disabled in the Corrections pane, so as to produce valid ASCII txt on output.
  • You could reenable these and then add Replacements in compile to turn them into XML or HTML entities, though.
  • A 12pt block cursor has been enabled. This will work best with fixed-width fonts.
  • Mac Only – Fixed-width editing settings are modified to closely emulate an 80-column width text editor.
  • For those who write with code samples, this can be useful for keeping your code readable in a context beyond Scrivener.

Also included, for Scrivener 3, is a project with a stylesheet that has been modified to present a less flamboyant and more “syntax highlighting” style approach to marking text. It also includes several character styles (Addition, Deletion and Highlight) which will by default generate CriticMarkup when using our provided Markdown-based compile formats, as well as two indexing styles, which will be made use of in Markdown outputs that support full indexing. To bring this stylesheet into your working project:

From your project, use the Format ▸ Style ▸ Import Styles… menu command.
Locate and open this project.
Confirm any overwrites or duplications of styles if need be.
Download for Mac 2

To use these preferences, download the zip file above, decompress it using the Finder by double-clicking on it. Then load up Scrivener’s Preference pane, and use the Manage… drop-down menu to “Load all preferences…”. Choose the .pref file with the file chooser, and click Okay.

Out of the box:

  • Ctl-A to beginning of line
  • Ctl-E to end of line
  • Sft-Ctl-A select to beginning of line
  • Sft-Ctl-E select to end of line

More here.

These keybindings will work in all applications in the whole system. You can easily use them in your IM client, or when writing a longer document. You don’t even need to restart, it’ll start working for all newly started applications. Here’s an example of some more Emacs style keybindings you might be used to from using the terminal.

{ "~d" = "deleteWordForward:"; "^w" = "deleteWordBackward:"; "~f" = "moveWordForward:"; "~b" = "moveWordBackward:"; }


You shouldn’t touch this XML file. instead you should make your modifications by creating the file:


Create Action pairs:

/* ~/Library/KeyBindings/DefaultKeyBinding.dict */ { "KEY1" = "ACTION1"; /* Bind KEY1 to ACTION1 */ "KEY2" = "ACTION2"; /* Bind KEY2 to ACTION2 */ ... }

An example is shown below:

/* ~/Library/KeyBindings/DefaultKeyBinding.dict */ { "~f" = "moveWordForward:"; /* Opt-f = next word */ "~b" = "moveWordBackward:"; /* Opt-b = previous word */ "~d" = "deleteWordForward:"; /* Opt-d = delete forward */ "~v" = "pageUp:"; /* Opt-v = page up */ "\UF729" = "moveToBeginningOfLine:"; /* Home = start of line */ "^\UF729" = "moveToBeginningOfDocument:"; /* Ctrl-Home = start of doc */ }

A key is defined either as a printable key character (e.g., “a”), or a non-printable key character in either octal (e.g, “\177″ for delete) or Unicode (e.g., “\UF700″ for up arrow) encoding. The key can be preceded by one or more key ‘modifiers’:

Key Modifiers

  • ^ : Ctrl
  • $ : Shift
  • ~ : Option (Alt)
  • @ : Command (Apple)
  • # : Numeric Keypad

One can easily customize the following

{ "~d" = "deleteWordForward:"; }

and save it under

A list of the most common non-printable key codes is shown below. A complete list can be found in the NSEvent.h header file.

Non-Printable Key Codes

Up Arrow: \UF700 Backspace: \U0008 F1: \UF704 Down Arrow: \UF701 Tab: \U0009 F2: \UF705 Left Arrow: \UF702 Escape: \U001B F3: \UF706 Right Arrow: \UF703 Enter: \U000A ... Insert: \UF727 Page Up: \UF72C Delete: \UF728 Page Down: \UF72D Home: \UF729 Print Screen: \UF72E End: \UF72B Scroll Lock: \UF72F Break: \UF732 Pause: \UF730 SysReq: \UF731 Menu: \UF735 Help: \UF746

Supported Actions

Supported Actions

alignCenter: newDocument: alignJustified: openDocument: alignLeft: orderBack: alignRight: orderFront: breakUndoCoalescing orderFrontLinkPanel: cancelOperation: orderFrontListPanel: capitalizeWord: orderFrontSpacingPanel: center orderFrontTablePanel: centerSelectionInVisibleArea: outline: changeCaseOfLetter: pageDown: checkSpelling: pageUp: clearRecentDocuments: paste: complete: pasteAsPlainText: copy: pasteAsRichText: copyFont: pasteFont: copyRuler: pasteRuler: cut: performClose: delete: performMiniaturize: deleteBackward: performZoom: deleteBackwardByDecomposingPreviousCharacter: printDocument: deleteForward: raiseBaseline: deleteToBeginningOfLine: revertDocumentToSaved: deleteToBeginningOfParagraph: runPageLayout: deleteToEndOfLine: saveAllDocuments: deleteToEndOfParagraph: saveDocument: deleteToMark: saveDocumentAs: deleteWordBackward: saveDocumentTo: deleteWordForward: scrollLineDown: hide: scrollLineUp: ignoreSpelling: scrollPageDown: indent: scrollPageUp: insertBacktab: selectAll: insertContainerBreak: selectLine: insertLineBreak: selectParagraph: insertNewline: selectToMark: insertNewlineIgnoringFieldEditor: selectWord: insertParagraphSeparator: setMark: insertTab: showContextHelp: insertTabIgnoringFieldEditor: showGuessPanel: insertText: startSpeaking: loosenKerning: stopSpeaking: lowerBaseline: subscript: lowercaseWord: superscript: moveBackward: swapWithMark: moveBackwardAndModifySelection: terminate: moveDown: tightenKerning: moveDownAndModifySelection: toggleBaseWritingDirection: moveForward: toggleContinuousSpellChecking: moveForwardAndModifySelection: toggleRuler: moveLeft: transpose: moveLeftAndModifySelection: transposeWords: moveRight: turnOffKerning: moveRightAndModifySelection: turnOffLigatures: moveToBeginningOfDocument: underline: moveToBeginningOfDocumentAndModifySelection: unscript: moveToBeginningOfLine: uppercaseWord: moveToBeginningOfLineAndModifySelection: useAllLigatures: moveToBeginningOfParagraph: useStandardKerning: moveToEndOfDocument: useStandardLigatures: moveToEndOfDocumentAndModifySelection: yank: moveToEndOfLineAndModifySelection: moveToEndOfLine: moveToEndOfParagraph: moveUp: moveUpAndModifySelection: moveWordBackward: moveWordBackwardAndModifySelection: moveWordForward: moveWordForwardAndModifySelection: moveWordLeft: moveWordLeftAndModifySelection: moveWordRight:

An example key binding file for partial Windows emulation.

/* ~/Library/KeyBindings/DefaultKeyBinding.dict */ { "^\010" = "deleteWordBackward:"; "\UF729" = "moveToBeginningOfLine:"; "^\UF729" = "moveToBeginningOfDocument:"; "$\UF729" = "moveToBeginningOfLineAndModifySelection:"; "^$\UF729" = "moveToBeginningOfDocumentAndModifySelection:"; "\UF72B" = "moveToEndOfLine:"; "^\UF72B" = "moveToEndOfDocument:"; "$\UF72B" = "moveToEndOfLineAndModifySelection:"; "^$\UF72B" = "moveToEndOfDocumentAndModifySelection:"; "^\UF702" = "moveWordLeft:"; "^\UF703" = "moveWordRight:"; "\UF72C" = "pageUp:"; "\UF72D" = "pageDown:"; "^z" = "undo:"; "$\UF728" = "cut:"; "$\UF746" = "paste:"; "^\UF746" = "copy:"; "$\UF700" = "moveUpAndModifySelection:"; "$\UF701" = "moveDownAndModifySelection:"; "$\UF702" = "moveLeftAndModifySelection:"; "$\UF703" = "moveRightAndModifySelection:"; "^$\UF702" = "moveWordLeftAndModifySelection:"; "^$\UF703" = "moveWordRightAndModifySelection:"; }

Example key binding file for partial Emacs emulation.

/* ~/Library/KeyBindings/DefaultKeyBinding.dict */ /* The original bindings are from Mike Ferris of as shipped * with his TextExtras package. They were further modified by Mishka Gorodnitzky * (, Patrick Linskey, and Llew Mason. */ { "~f" = "moveWordForward:"; /* M-f */ "~b" = "moveWordBackward:"; /* M-b */ "~<" = "moveToBeginningOfDocument:"; /* M-< */ "~>" = "moveToEndOfDocument:"; /* M-> */ "~v" = "pageUp:"; /* M-v */ "^v" = "pageDown:"; /* C-v */ "~d" = "deleteWordForward:"; /* M-d */ "~^h" = "deleteWordBackward:"; /* M-C-h */ "~\010" = "deleteWordBackward:"; /* M-backspace */ "~\177" = "deleteWordBackward:"; /* M-delete */ "~\UF728" = "deleteWordForward:"; /* delete */ "\UF729" = "moveToBeginningOfDocument:"; /* home */ "\UF72B" = "moveToEndOfDocument:"; /* end */ "@\UF729" = "moveToBeginningOfParagraph:"; /* A-home */ "@\UF72B" = "moveToEndOfParagraph:"; /* A-end */ "@\UF700" = "moveToBeginningOfDocument:"; /* A-up */ "@\UF701" = "moveToEndOfDocument:"; /* A-down */ "^\UF700" = "pageUp:"; /* C-up */ "^\UF701" = "pageDown:"; /* C-down */ "\UF72C" = "pageUp:"; /* page-up */ "\UF72D" = "pageDown:"; /* page-down */ "^/" = "undo:"; /* C-/ */ "~c" = "capitalizeWord:"; /* M-c */ "~u" = "uppercaseWord:"; /* M-u */ "~l" = "lowercaseWord:"; /* M-l */ "^t" = "transpose:"; /* C-t */ "~t" = "transposeWords:"; /* M-t */ "~/" = "complete:"; /* M-/ */ "^g" = "_cancelKey:"; /* C-g */ "^a" = "moveToBeginningOfLine:"; /* C-a */ "^e" = "moveToEndOfLine:"; /* C-e */ "^x" = { "^x" = "swapWithMark:"; /* C-x C-x */ "^m" = "selectToMark:"; /* C-x C-m */ "^s" = "save:"; /* C-x C-s */ "^w" = "saveAs:"; /* C-x C-w */ "k" = "performClose:"; /* C-x C-k */ }; /* Mark-point stuff (Emacs-style mark and point bindings are * implemented but not bound by default. In the text system the * mark and point are ranges, not just locations. The "point" is * the selected range.) */ "^@" = "setMark:"; /* C-@ */ "^ " = "setMark:"; /* C-space */ "^w" = "deleteToMark:"; /* C-w */ /* Mac Style F1-F5 bindings */ "\UF704" = "undo:"; /* F1 */ "\UF705" = "cut:"; /* F2 */ "\UF706" = "copy:"; /* F3 */ "\UF707" = "paste:"; /* F4 */ "\UF708" = "_cancelKey:"; /* F5 */ }