MultiMarkdown Composer v4 Themes

Background

Composer v2 supported Style Sheet (aka "Styles"). These were written in Apple's Property List format and allowed custom styling for the editor as well as CSS for the Preview.

Composer v3 (beta) changed a few things:

  1. Renamed Style Sheets to "Themes". For some reason people kept confusing them with CSS, even though they look completely different. Whatever. ;)

  2. The format was still Plist, but the keys were changed slightly and they used a new file extension for disambiguation.

Composer v4 changes things again, to a much better option.

MultiMarkdown Composer Themes (V4)

Themes for v4 are written in JSON. At a superficial level it is similar to the Plist format, but is more flexible and more commonly supported. (In fact, all of the customization files for v4 are written in JSON.) I did this because:

  1. I can use a standard library to parse and load these files on any platform, not just macOS or iOS.

  2. The JSON format is widely used and supported, so you can use JSON-aware editors to help you troubleshoot your changes while editing.

  3. The library I wrote to handle themes for syntax highlighting (and the other features) are written in cross-platform C -- it didn't make sense to stick with a format limited to macOS/iOS devices.

There are many resources online to teach you about the JSON format. Google your own to learn the basics, but you'll probably pick it up along the way.

Colors

Colors are specified using standard/common HTML notation:

  • #RRGGBB - no alpha
  • #RRGGBBAA - support for alpha
  • #RGB - single digit variant
  • RRGGBB - # is optional

Global Properties

There are several properties that apply to the entire window/document:

  • selectionColor - color applied to selected text
  • caretColor - color applied to the insertion marker ("caret")
  • lineHeight - line height spacing (e.g. 2.0 = double spaced lines) (Overrides application preferences)
  • horizontalPadding - left/right padding around the entire document ("margins") (Overrides application preferences)
  • verticalPadding - top/bottom padding (Overrides application preferences)
  • sidebarBackgroundColor - background color for the sidebars (e.g. the Table of Contents table)
  • sidebarTextColor - text color for text in the sidebar tables
  • sidebarTextColorHighlighted - text color when an item is selected in the table
  • sidebarTextColorHighlightedInactive - text color when the table loses focus
  • sidebarHighlightColor - highlight color for selected item in the table
  • sidebarHighlightColorInactive - highlight color when table loses focus

These properties are ignored anywhere other than the document root.

Element Properties

Individual elements in the text can have custom properties applied (including the document root, where these are applied as default to the entire text):

  • foregroundColor - text color for element
  • backgroundColor - background color for element
  • fontName - name of the desired font (you can only choose one, so choose carefully. ;) (Overrides application preferences)
  • fontSize - size for the text of the element (Overrides application preferences)
  • fontScale - apply a relative size instead of an absolute size. (Overrides application preferences)
  • bold - apply bold styling (if available), 1 = enable
  • italic - apply italics (if available), 1 = enable
  • underline - apply different styles of underlining. 0 = disable, other numbers use different styles according to your operating system. I recommend 1 for simplicity, but you can try larger numbers.
  • superscript - raise the element above the text baseline
  • subscript - lower the element below the text baseline
  • leftIndent - Indent element from the left margin
  • leftFirstIndent - Separate left indent for first line of text that wraps across multiple lines in the text view (Remember that a paragraph in Markdown can consist of multiple lines of text, but that return or enter splits text into multiple paragraphs in macOS and iOS. You'll have to decide how you want to handle this.)
  • rightIndent - Indent from the right margin
  • paraSpaceBefore - extra spacing before a paragraph
  • paraSpace - extra spacing after a paragraph
  • textAlignment -- apply specific text alignment styles, 1 = left, 2 = right, 3 = justified, 4 = center

Element Names

The elements currently available for customization include (NOTE: Indented lists inherit properties from their ancestors. For example pairs->brackets->abbreviation. This limits repetition while preserving flexibility):

  • CriticMarkup
    • criticAddition - CriticMarkup insertion
    • criticDeletion - CriticMarkup deletion
    • criticComment - CriticMarkup comment
    • criticHighlight - CriticMarkup highlight
    • criticSubstitution - CriticMarkup substitution
  • Block elements
    • blockquote - block quotes
    • codeBlock - indented or fenced code blocks
    • math - math block
    • metadata - document metadata
    • table - tables
  • Definition lists
    • definitionList -- Definition lists
    • definition -- Individual definition
  • Headings
    • heading - default for all headings
    • heading1 - level 1 heading (e.g. # foo #)
    • heading2
    • heading3
    • heading4
    • heading5
    • heading6
  • HTML
    • html - HTML elements
      • htmlComment - HTML comments (e.g. <!-- foo -->) (NOTE: An html comment that is a Markdown block by itself will be considered html, not htmlComment)
  • Lists
    • bulletList - bulleted lists (e.g * foo)
    • orderedList - enumerated lists (e.g. 1. foo)
    • listItem- individual list items
  • Reference definitions
    • definitionAbbreviation - abbreviation definitions (e.g. [>foo]: bar)
    • definitionCitation - citation definitions (e.g. [#foo]: bar)
    • definitionFootnote - footnote definitions (e.g. [^foo]: bar)
    • definitionGlossary - glossary definitions (e.g. [?foo]: bar)
    • definitionLink - link definitions (e.g. [foo]: bar)
  • Text elements
    • codeSpan - code text (e.g. `foo`)
    • emphasis - emphasized text (e.g. *foo*)
    • strong - strong text (e.g. **foo**)
    • superscript - superscripts (e.g. m^2^) (NOTE: Does not currently work on m^2)
    • subscript - subscripts (e.g. x~y~)
  • Paired elements
    • pairs - generic styling for paired elements (e.g. those that start and end with paired characters such as "...")
      • angles - paired angle markers (<...>)
      • braces - paired braces ({...})
      • brackets - specific styling for paired brackets ([...])
        • abbreviation - abbreviation brackets ([>...])
        • citation - citation brackets ([#...])
        • footnote - footnote brackets ([^...])
        • glossary - glossary brackets ([?...])
        • image - image brackets (![...])
        • variable - variable brackets ([%...])
      • parens - paired parenthesis ((...))
      • quoteDouble - paired double quotation marks ("...")
      • quoteSingle - paired single quotation marks ('...')
  • Other
    • markup - styling for characters used in MultiMarkdown markup
      • hr -- horizontal rules (e.g. ----)
      • toc -- Table of Contents marker (e.g. {{TOC}})

Previews

The preview pane is no longer controlled by Themes. They use a regular CSS file that can be chosen (and customized) independently from the editor themes.

Comments

You'll notice that there is not a specific styling for links as opposed to regular brackets. This is because there is not a separate markup to disambiguate links without a bit of processing.

For example, [foo] could be a link if there is a definition for it in the document, otherwise it's just text in some brackets.

However, [foo](bar) will apply the same bracket styling to the (bar) if it immediately follows [foo], since that implies that a link is intended.

Suggestions

If you're going to customize themes, I recommend the following:

  1. Start by adjusting an existing theme to get the hang of things. The themes that come with Composer make use of most of the features and show you the general idea.

  2. When building your own, make use of the cascading design. For example, create a style for all headings, and then change what needs to be changed for specific instances. Maybe you want level 1 headings to be a different size, but all colors should be the same.

  3. Be aware that specifying certain properties will override the user's preferences and may lead to confusion. If you intend to share your theme with others, only use those properties if you have a good reason.

  4. The Empty.theme is designed to be a starting place. It applies white background, black text, standard Aqua colors for the sidebars, and "standard" CriticMarkup colors. It sets a monospaced font for code (Courier), a few indented margins, and a basic markup color. Otherwise it's pretty empty.