Repository navigation
0.23.0
Changes
- A markdown parser written for formatting (#224, #260). The plugin no longer goes through
pulldown-cmark. The new parser keeps what a formatter needs and a renderer throws away — exact delimiters, indentation, line breaks, link reference definitions — which is what makes most of the fixes below possible. - Html is formatted now (#255, #257, #260). Tags, attributes, and their content get laid out rather than passed through untouched, with a set of
html.*options to control it, includinghtml.skipFormatto turn it back off. - Definition lists are supported (#211).
- Options moved under namespaces —
heading.,list.,codeBlock., andtable.(#225, #250, #260).
Performance
Measured over a corpus of 3,532 real-world markdown files (21.8 MB), code block formatting disabled, best of three runs on the same machine:
| 0.22.1 | 0.23.0 | ||
|---|---|---|---|
| Time | 964 ms | 347 ms | 2.8x faster |
| Allocations | 10.4M | 1.2M | 8.7x fewer |
| Bytes allocated | 6.5 GB | 0.8 GB | 8.4x less |
| Throughput | 23 MB/s | 63 MB/s |
That is with 0.23.0 doing strictly more work, since it also parses and formats every piece of html in those files, which 0.22.1 didn't do at all. 0.22.1 also failed outright on 22 of the 3,532 files; 0.23.0 formats all of them (#254).
Breaking changes
Options moved under namespaces
The old names still work, and dprint config update will now rewrite them for you (#225, #250, #260):
| Old | New |
|---|---|
headingKind |
heading.kind |
unorderedListKind |
list.unorderedMarker |
listIndentKind |
list.indentKind |
The old names will continue to work for the foreseeable future.
Html
html.skipFormat(defaultfalse) — leave the html written in the file as it was rather than laying out its tags and their content (#255).html.useTabs(default: the globaluseTabs, elsefalse) andhtml.indentWidth(default: the globalindentWidth, else2) — how the html inside the file is indented (#255).html.selfClosingSpace(defaulttrue) — whether to write a space before the/>of a self-closing tag, so<br />rather than<br/>(#255).html.preferSingleLine(defaultfalse) — whether to pull an element's content, or a tag's attributes, onto one line when they fit. Off by default, so content written across lines stays across lines and is only reindented (#259).- The indentation of an html block's first line is maintained (#218), and an html block that formatting would otherwise cut short is kept whole (#257).
New configuration
Text wrapping
textWrap: "sentence"(#239) — one sentence per line, ignoring the line width. This is the mechanical half of semantic line breaks: a break goes where a sentence ends and nowhere else, so a diff stays scoped to the sentences you actually edited.textWrap: "maintainAndWrap"(#251) — keeps the line breaks that were written but breaks up any line running past the line width. No line is ever pulled up into the one above it.wrapUnspacedScripts(defaultfalse) — whether to break a line between the characters of a script written without spaces between its words, such as Chinese or Japanese. Off by default, because Chromium and WebKit render such a break as a space (Firefox doesn't), so a break the formatter wrote would show up in the rendered text for most readers (#231, #258).
Blank lines
maxBlankLines(default1) — the maximum number of consecutive blank lines to keep between blocks (#236).heading.blankLinesAbove(default: unset) — the number of blank lines to write above a heading, written even wheremaxBlankLinesis lower. A heading drawn up against the block above it inside a list is left there, which keeps the list tight (#249).
Hard breaks
hardBreakKind(default"backslash") — write hard line breaks as a trailing backslash or as two trailing spaces ("doubleSpace"). Note that plenty of tools strip trailing whitespace, which would silently delete double-space breaks. Those two spaces don't count toward the line width (#217, #229).
Code blocks
codeBlock.skipFormat(defaultfalse) — leave the code inside code blocks as it was written (#226).codeBlock.raiseSyntaxErrors(defaultfalse) — fail the file when the plugin formatting a code block reports an error, which is what it does when the code doesn't parse, rather than leaving that code alone (#252).codeBlock.useTabsandcodeBlock.indentWidth(default: unset) — override those settings on the plugin that formats the code within a code block instead of leaving them to that plugin (#232, #235).codeBlock.preserveIndentation(defaultfalse) — keep an indented code block's indentation rather than unindenting it (#175, #225).codeBlock.preserveBlankLines(defaultfalse) — keep the leading blank lines inside a fenced code block (#204, #225).
Tables
table.skipFormat(defaultfalse) — leave a table's rows as they were written instead of aligning their cells into columns (#247).table.cellPadding(default"align") —"align"pads every cell out to its column's width, so editing one cell can rewrite every row;"space"writes a single space either side of the text;"none"writes no padding at all (#248).
Fixes
Link reference definitions
- Definitions are no longer dropped, including one that is a list item's only content and ones written inside a list item, and adjacent nodes are no longer separated (#198, #205, #210, #212).
- A link reference is written in the same style as inline links, destinations are escaped correctly, image destinations are formatted, and tabs and line endings within a destination are handled. An inline link's URI is enclosed in pointy brackets where it needs to be (#196, #197).
- Shortcut reference images are supported (#190).
- A line break in an image's alt text, a title, or a reference label is kept (#199), as is one within a link's text (#215).
Block quotes
- The marker is kept when it doesn't start a line and for empty block quotes (#188), on lines within a link or a setext heading (#206), and on a line holding only a hard break (#234).
- Blank lines between the paragraphs of a list item in a block quote are kept (#189).
- A block quote within a list within a block quote is handled (#200).
Headings
- An ATX heading is used where a setext heading would come out empty (#219).
- A setext heading whose text begins a block is no longer underlined (#237).
Hard breaks and line wrapping
- A hard break is turned into a space where it can't be a hard break (#216), and a backslash is written where two spaces wouldn't read as one (#244).
- No backslash hard break is written after a callout header (#213).
- A line break between CJK characters is no longer turned into a space, whether it falls in plain text, through emphasis, or through a link (#230, #238, #241).
- Text that would start a block is kept off the start of a line (#233), as are the words of a thematic break (#240) and a code span's words where the line would read as a block (#243).
- Line wrapping within inline code works (#130).
Code spans and code blocks
- The shortest possible backtick delimiter is used for a code span (#201).
- A code span that is only whitespace is no longer trimmed (#209).
- The
cpptag maps to the.cppextension (#214).
Other
- A list is written beside the marker of the item that holds only it (#245).
- Escaped characters are ignored when looking for a container's closing character (#131, #193).
Install
Then in your project's dprint configuration file:
- Specify the plugin url in the
"plugins"array or rundprint config add markdown. - Add a
"markdown"configuration property if desired.
JS Formatting API
- JS Formatter - Browser/Deno and Node
- npm package
{ // ...etc... "markdown": { // markdown config goes here }, "plugins": [ "npm:@dprint/markdown@0.23.0" ] }