MultiMarkdown Composer v5 Themes
(NOTE: This is a draft document. Feedback welcome!)
Introduction
The format for themes has been redesigned for consistency and flexibility. v2 of the theme syntax is used for both nvUltra and MultiMarkdown Composer v5.
v2 Themes are similar to the JSON theming used in MultiMarkdown Composer 4, but there are some differences. This document describes how these files work, and how you can modify them.
Themes are used to control two separate things:
- Window chrome styling (e.g. window background color, table colors, etc.)
- Syntax highlighting attributes for MultiMarkdown syntax
File Location
For nvUltra and MultiMarkdown Composer, Themes (and other customization files) are located in your ~/Library folder. The easiest way to locate them is through the application's Preferences dialog. In the Appearance tab, for example, you can use the Open Themes Button
to go directly to the proper folder.
The same folders are used for nvUltra and MultiMarkdown Composer v5, so that you have the same customizations available for both applications.
File Format
Themes for nvUltra and MultiMarkdown Composer are written in JSON.
If you are having trouble, a good first step is to ensure that your file is written in valid JSON. A good place to do that is here.
Colors
Colors are specified using standard/common HTML notation:
#RRGGBB
- no alpha#RRGGBBAA
- support for alpha#RGB
- single digit variant#RGBA
- single digit with alphaRGB
/RRGGBB
-#
is optional
Window Chrome
Themes are used to style various elements within the windows:
searchField
tableView
tableViewHighlighted
tableViewInactive
textView
window
Attributes applied at the top level serve as a default for all elements.
Window Chrome Example
{
"darkWindow" : true,
"lightWindow" : false,
"transparentTitlebar" : true,
"backgroundColor" : "#43484C",
"foregroundColor" : "#dddddd",
"selectionBackgroundColor" : "#990000",
"caretColor" : "#eeeeee",
"searchField" : {
"backgroundColor" : "#6B7277"
},
"tableView" : {
"fontName" : "Avenir",
"fontSize" : 14,
"rowHeight" : 34,
"drawFocusRing" : false,
"drawBorder" : false,
"horizontalPadding" : 8,
"verticalPadding" : 0
},
"tableViewHighlighted" : {
"backgroundColor" : "#990000"
},
"tableViewInactive" : {
"backgroundColor" : "#dddddd",
"foregroundColor" : "#990000"
},
"textView" : {
"backgroundColor" : "#eeeeee",
"foregroundColor" : "#000",
"selectionBackgroundColor" : "#bbb",
"caretColor" : "#000"
}
}
This example sets top level default values, and then overrides for specific elements where appropriate.
Window Chrome Attributes
Top level elements include:
darkWindow
- boolean to force macOS dark modelightWindow
- boolean to force macOS light modetransparentTitlebar
- boolean to use transparent titlebar style for the window's titlebar
The attributes used for individual elements include:
backgroundColor
- Color applied to backgroundcaretColor
- Color for the insertion point caretdrawFocusRing
- Boolean to specify whether table should draw a focus ringdrawBorder
- Boolean to specifiy whether table should draw a surrounding border framefontName
- The name of the font to use, must match the name expected by the systemfontScale
- Relative size to element based on size of parent elementfontSize
- Absolute size to apply to fontforegroundColor
-- Color applied to texthorizontalPadding
- Specify horizontal margins in tablesrowHeight
- Specify row height for tablesselectionBackgroundColor
- Background color for selected textselectionForegroundColor
- Foreground color for selected textverticalPadding
- Specify vertical margins in tables
(Not every attribute is used for every element type)
Syntax Highlighting Example
A basic example of the syntax highlighting functionality:
{
"foregroundColor" : "#dddddd",
"backgroundColor" : "#43484C",
"markup" : {
"foregroundColor" : "#40607F"
},
"strong" : {
"bold" : 1,
"markupForegroundColor" : "#F00"
},
"emphasis" : {
"italic" : 1,
"markupForegroundColor" : "#0F0"
}
}
This simple example sets a default foreground and background color, then adds a different foreground color for all markup elements. Strong (bold) elements are set to use a bold font variant, and use a different markup color. Similarly, emphasis (italics) use an italicized font variant and custom markup color.
Syntax Highlighting Element Properties
Each element can be assigned the following properties
backgroundColor
- Color applied to backgroundbold
- Boolean to apply bold font stylefontName
- The name of the font to use, must match the name expected by the systemfontScale
- Relative size to element based on size of parent elementfontSize
- Absolute size to apply to fontforegroundColor
- Color applied to textitalic
- Boolean to apply italicized font styleleftIndent
- Left margin to apply (block level elements only)leftFirstIndent
- Separate indentation for the first line of a paragraph (block level elements only)markupBackgroundColor
- Background color applied to markup elements (if appropriate)markupForegroundColor
- Color applied to markup elements (if appropriate)mono
- Boolean value to apply a monospace fontparaSpace
- Space between paragraphs (measured in units of font size) (block level elements only)paraSpaceBefore
- Space between start of paragraph and its content (measured in units of font size) (block level elements only)rightIndent
- Right margin to apply (block level elements only)superscript
- Apply supescript vertical alignment style (1 = superscript, -1 = subscript)textAlignment
- Apply text alignment style (0 = natural, 1 = left, 2 = right, 3 = justified, 4 = center) (block level elements only)underline
- Apply underline style (0 = disable, other numbers based on operating system. I recommend starting with 1 and experimenting.)writingDirection
- Right-to-left, Left-to-Right, etc. (0 = natural, 1 = LTR, 2 = RTL ) (block level elements only)
Syntax Highlighting Element Names
This is a list of the various element types that can be included in your theme file. They are broken into groups of related elements, and include the key used in the theme file, followed by a short description, followed by the token type used by MultiMarkdown. This last part is generally only useful for developers who are using libMultiMarkdown in their own projects.
Sometimes multiple token types are set to the same values (e.g. BLOCK_H1
and BLOCK_SETEXT_1
). They may appear more than once in the tables, even though you can't set them to different values.
-
Sample element
sampleThemeName
- Optional description (MMD TOKEN NAME - useful for developers using libMultiMarkdown in their own projects)
-
Blocks
blockquote
- Block quote (BLOCK_BLOCKQUOTE)codeBlock
- Indented code block (BLOCK_CODE_INDENTED)codeBlock
- Fenced code block (BLOCK_CODE_FENCED)definitionList
- Definition list (BLOCK_DEFLIST)definition
- Individual definition (BLOCK_DEFINITION)metadata
- Document metadata (BLOCK_META)table
- Table (BLOCK_TABLE)
-
CriticMarkup
criticAddition
- CriticMarkup insertion (PAIR_CRITIC_ADD)criticComment
- CriticMarkup comment (PAIR_CRITIC_COM)criticDeletion
- CriticMarkup deletion (PAIR_CRITIC_DEL)criticHighlight
- CriticMarkup highlighting (PAIR_CRITIC_HI)criticSubstitution
- CriticMarkup substitution (deletion component) (PAIR_CRITIC_SUB_DEL)criticSubstitution
- CriticMarkup substitution (insertion component) (PAIR_CRITIC_SUB_ADD)
-
HTML
htmlComment
- HTML comments (e.g.<!-- foo -->
) (PAIR_HTML_COMMENT)html
- Raw HTML elements (BLOCK_HTML)html
- HTML character entities (e.g.©
) (HTML_ENTITY)
-
Headings
heading
- Default properties for all headings (BLOCK_HEADING)heading1
- Level 1 heading (e.g.# foo #
) (BLOCK_H1)heading2
- Level 2 heading (e.g.## foo ##
) (BLOCK_H2)heading3
- Level 3 heading (e.g.### foo ###
) (BLOCK_H3)heading4
- Level 4 heading (e.g.#### foo ####
) (BLOCK_H4)heading5
- Level 5 heading (e.g.##### foo #####
) (BLOCK_H5)heading6
- Level 6 heading (e.g.###### foo ######
) (BLOCK_H6)heading1
- Level 1 Setext heading (BLOCK_SETEXT_1)heading2
- Level 2 Setext heading (BLOCK_SETEXT_2)
-
Lists
bulletList
- Bulleted list (BLOCK_LIST_BULLETED)bulletList
- Bulleted list with implied<p>
(BLOCK_LIST_BULLETED_LOOSE)orderedList
- Enumerated list (BLOCK_LIST_ENUMERATED)orderedList
- Enumerated list with implied<p>
(BLOCK_LIST_ENUMERATED_LOOSE)listItem
- Individual list item (BLOCK_LIST_ITEM)listItem
- Single line list item (BLOCK_LIST_ITEM_TIGHT)
-
Markup
markup
- General markup formatting (MARKUP)toc
- Table of contents (BLOCK_TOC)hr
- Horizontal rule (divider line) (BLOCK_HR)
-
Math
math
- MultiMarkdown parenthetical math (e.g.\\(...\\)
) (PAIR_MATH)math
- MultiMarkdown bracketed math (e.g.\\[...\\]
) (PAIR_MATH)math
- MultiMarkdown dollar math (e.g.$...$
or$$...$$
) (PAIR_MATH)
-
Paired Parentheses
linkParens
- URL portion of an inline link (e.g.[foo](bar)
) (PAIR_PAREN_LINK)
-
Pairs
pairs
- Generic styling for paired elements (e.g. those that start and end with paired characters such as"..."
) (PAIRS)angles
- Paired angle markers (e.g.<...>
) (PAIR_ANGLE)braces
- Paired braces (e.g.{...}
) (PAIR_BRACE)bracesDouble
- Paired double braces (e.g.{{...}}
) (PAIR_BRACES)brackets
- Paired brackets (e.g.[...]
) (PAIR_BRACKET)parens
- Paired parentheses (e.g.(...)
) (PAIR_PAREN)quoteDouble
- Paired double quotation marks (e.g."..."
) (PAIR_QUOTE_DOUBLE)quoteSingle
- Paired single quotation marks (e.g.'...'
) (PAIR_QUOTE_SINGLE)
-
Pairs - Brackets
abbreviation
- Abbreviation brackets (e.g.[>foo]
) (PAIR_BRACKET_ABBREVIATION)citation
- Citation brackets (e.g.[#foo]
) (PAIR_BRACKET_CITATION)footnote
- Footnote brackets (e.g.[^foo]
) (PAIR_BRACKET_FOOTNOTE)glossary
- Glossary brackets (e.g.[?foo]
) (PAIR_BRACKET_GLOSSARY)image
- Image brackets (e.g.![foo]
) (PAIR_BRACKET_IMAGE)variable
- Variable brackets (e.g.[%foo]
) (PAIR_BRACKET_VARIABLE)
-
References
definitionAbbreviation
- Abbreviation definition (e.g.[>foo]: bar
) (BLOCK_DEF_ABBREVIATION)definitionCitation
- Citation definition (e.g.[#foo]: bar
) (BLOCK_DEF_CITATION)definitionFootnote
- Footnote definition (e.g.[^foo]: bar
) (BLOCK_DEF_FOOTNOTE)definitionGlossary
- Glossary definition (e.g.[?foo]: bar
) (BLOCK_DEF_GLOSSARY)definitionLink
- Link/URL definition (e.g.[foo]: bar
) (BLOCK_DEF_LINK)
-
Spans
codeSpan
- Code text (e.g.`foo`
) (PAIR_BACKTICK)emphasis
- Emphasized text (e.g.*foo*
) (PAIR_EMPH)strong
- Strong text (e.g.**foo**
) (PAIR_STRONG)subscript
- Subscript (e.g.x~y~
) (PAIR_SUBSCRIPT)superscript
- Superscript (e.g.m^2^
)(NOTE: Does not currently work onm^2
) (PAIR_SUPERSCRIPT)
Style "Cascading"
All syntax highlighting elements inherit attributes from root level attributes. For example, you can set a default foregroundColor
, which is then inherited by all other elements.
Additionally, some syntax highlighting elements inherit their formatting from a "parent" element, but can be overridden for more flexibility.
{
"foregroundColor" : "#F00",
"heading" : {
"foregroundColor" : "#0F0"
},
"heading1" : {
"foregroundColor" : "#00F"
}
}
In this example, the default text color is red (#F00
), which is inherited by all elements. heading
overrides this with a green (#0F0
) foreground for all headings. Except for level 1 headers (# Foo #
), which further override the text color to blue (#00F
).
This inheritance model (somewhat similar in philosophy to CSS) offers a great deal of flexibility, while also allowing you to minimize duplicating attributes that are used throughout the document.
This lists the parent token types along with their "children":
definitionList
- (BLOCK_DEFLIST)
definition
- Individual definition (BLOCK_DEFINITION)
heading
- (BLOCK_HEADING)
heading1
- Level 1 heading (e.g.# foo #
) (BLOCK_H1)heading2
- Level 2 heading (e.g.## foo ##
) (BLOCK_H2)heading3
- Level 3 heading (e.g.### foo ###
) (BLOCK_H3)heading4
- Level 4 heading (e.g.#### foo ####
) (BLOCK_H4)heading5
- Level 5 heading (e.g.##### foo #####
) (BLOCK_H5)heading6
- Level 6 heading (e.g.###### foo ######
) (BLOCK_H6)heading1
- Level 1 Setext heading (BLOCK_SETEXT_1)heading2
- Level 2 Setext heading (BLOCK_SETEXT_2)
html
- (BLOCK_HTML)
htmlComment
- HTML comments (e.g.<!-- foo -->
) (PAIR_HTML_COMMENT)
markup
- (MARKUP)
toc
- Table of contents (BLOCK_TOC)hr
- Horizontal rule (divider line) (BLOCK_HR)
pairs
- (PAIRS)
angles
- Paired angle markers (e.g.<...>
) (PAIR_ANGLE)braces
- Paired braces (e.g.{...}
) (PAIR_BRACE)bracesDouble
- Paired double braces (e.g.{{...}}
) (PAIR_BRACES)brackets
- Paired brackets (e.g.[...]
) (PAIR_BRACKET)parens
- Paired parentheses (e.g.(...)
) (PAIR_PAREN)quoteDouble
- Paired double quotation marks (e.g."..."
) (PAIR_QUOTE_DOUBLE)quoteSingle
- Paired single quotation marks (e.g.'...'
) (PAIR_QUOTE_SINGLE)
brackets
- (PAIR_BRACKET)
abbreviation
- Abbreviation brackets (e.g.[>foo]
) (PAIR_BRACKET_ABBREVIATION)citation
- Citation brackets (e.g.[#foo]
) (PAIR_BRACKET_CITATION)footnote
- Footnote brackets (e.g.[^foo]
) (PAIR_BRACKET_FOOTNOTE)glossary
- Glossary brackets (e.g.[?foo]
) (PAIR_BRACKET_GLOSSARY)image
- Image brackets (e.g.![foo]
) (PAIR_BRACKET_IMAGE)variable
- Variable brackets (e.g.[%foo]
) (PAIR_BRACKET_VARIABLE)
parens
- (PAIR_PAREN)
linkParens
- URL portion of an inline link (e.g.[foo](bar)
) (PAIR_PAREN_LINK)
How to Customize Themes
If you're going to customize themes, I recommend the following:
-
Start by duplicating an existing theme and then modifying it gradually 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.
-
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.
-
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.
fontName
,fontSize
, andwritingDirection
are some examples of keys to use cautiously.