Skip to content

Commit

Permalink
feat(markdown): add proseWrap: "preserve" option (#3340)
Browse files Browse the repository at this point in the history
* test: add test case

* feat(markdown): add `proseWrap: "preserve"` option

* test: add tests

* docs(options): update `proseWrap`

* feat(markdown): change default to `proseWrap: "preserve"`

BREAKING CHANGE

* docs(options): update `proseWrap`

* test: specify option explicitly

* Fix lint after merge

* Fix error after merge
  • Loading branch information
ikatyang authored and azz committed Dec 1, 2017
1 parent d52d721 commit 073c0b1
Show file tree
Hide file tree
Showing 40 changed files with 293 additions and 68 deletions.
14 changes: 10 additions & 4 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,14 @@ Prettier can insert a special @format marker at the top of files specifying that

_available in v1.8.2+_

By default, Prettier will wrap markdown text at the specified print width. In some cases you may want to rely on editor/viewer soft wrapping instead, so this option allows you to opt out. When prose wrapping is disabled, each paragraph will be printed on its own line.
By default, Prettier will wrap markdown text as-is since some services use a linebreak-sensitive renderer, e.g. GitHub comment and BitBucket. In some cases you may want to rely on editor/viewer soft wrapping instead, so this option allows you to opt out with `"never"`.

| Default | CLI Override | API Override |
| ------- | ----------------- | ------------------- |
| `true` | `--no-prose-wrap` | `proseWrap: <bool>` |
Valid options:

* `"always"` - Wrap prose if it exceeds the print width.
* `"never"` - Do not wrap prose.
* `"preserve"` - Wrap prose as-is. _available in v1.9.0+_

| Default | CLI Override | API Override |
| ------------ | ----------------------------------------------------------- | ----------------------------------------------------------- |
| `"preserve"` | <code>--prose-wrap <always&#124;never&#124;preserve></code> | <code>proseWrap: "<always&#124;never&#124;preserve>"</code> |
4 changes: 4 additions & 0 deletions src/clean-ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ function massageAST(ast, parent) {
if (ast.type === "code") {
delete newObj.value;
}
// for markdown whitespace: "\n" and " " are considered the same
if (ast.type === "whitespace" && ast.value === "\n") {
newObj.value = " ";
}

if (
ast.type === "media-query" ||
Expand Down
14 changes: 11 additions & 3 deletions src/cli-constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,19 @@ const detailedOptions = normalizeDetailedOptions({
description: "The line length where Prettier will try wrap."
},
"prose-wrap": {
type: "boolean",
type: "choice",
category: CATEGORY_FORMAT,
forwardToApi: true,
description: "Wrap prose if it exceeds the print width. (markdown)",
oppositeDescription: "Do not wrap prose. (markdown)"
description: "How to wrap prose. (markdown)",
choices: [
{
value: "always",
description: "Wrap prose if it exceeds the print width."
},
{ value: "never", description: "Do not wrap prose." },
{ value: "preserve", description: "Wrap prose as-is." },
{ value: false, deprecated: true, redirect: "never" }
]
},
"range-end": {
type: "int",
Expand Down
12 changes: 11 additions & 1 deletion src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const defaults = {
insertPragma: false,
requirePragma: false,
semi: true,
proseWrap: true,
proseWrap: "preserve",
arrowParens: "avoid"
};

Expand Down Expand Up @@ -72,6 +72,16 @@ function normalize(options) {
);
}

/* istanbul ignore if */
if (typeof normalized.proseWrap === "boolean") {
normalized.proseWrap = normalized.proseWrap ? "always" : "never";

console.warn(
"Warning: `proseWrap` with boolean value is deprecated. " +
'Use "always", "never", or "preserve" instead.'
);
}

/* istanbul ignore if */
if (normalized.parser === "postcss") {
normalized.parser = "css";
Expand Down
24 changes: 15 additions & 9 deletions src/printer-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function genericPrint(path, options, print) {
node =>
node.type === "word"
? node.value
: node.value === "" ? "" : printLine(path, line, options)
: node.value === "" ? "" : printLine(path, node.value, options)
)
);
}
Expand Down Expand Up @@ -99,12 +99,13 @@ function genericPrint(path, options, print) {
const index = parentNode.children.indexOf(node);
const nextNode = parentNode.children[index + 1];

// leading char that may cause different syntax
if (nextNode && /^>|^([-+*]|#{1,6}|[0-9]+[.)])$/.test(nextNode.value)) {
return node.value === "" ? "" : " ";
}
const proseWrap =
// leading char that may cause different syntax
nextNode && /^>|^([-+*]|#{1,6}|[0-9]+[.)])$/.test(nextNode.value)
? "never"
: options.proseWrap;

return printLine(path, node.value === "" ? softline : line, options);
return printLine(path, node.value, { proseWrap });
}
case "emphasis": {
const parentNode = path.getParentNode();
Expand Down Expand Up @@ -367,10 +368,15 @@ function getAncestorNode(path, typeOrTypes) {
return counter === -1 ? null : path.getParentNode(counter);
}

function printLine(path, lineOrSoftline, options) {
function printLine(path, value, options) {
if (options.proseWrap === "preserve" && value === "\n") {
return hardline;
}

const isBreakable =
options.proseWrap && !getAncestorNode(path, SINGLE_LINE_NODE_TYPES);
return lineOrSoftline === line
options.proseWrap === "always" &&
!getAncestorNode(path, SINGLE_LINE_NODE_TYPES);
return value !== ""
? isBreakable ? line : " "
: isBreakable ? softline : "";
}
Expand Down
7 changes: 5 additions & 2 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ function mapDoc(doc, callback) {
/**
* split text into whitespaces and words
* @param {string} text
* @return {Array<{ type: "whitespace", value: " " | "" } | { type: "word", value: string }>}
* @return {Array<{ type: "whitespace", value: " " | "\n" | "" } | { type: "word", value: string }>}
*/
function splitText(text) {
const KIND_NON_CJK = "non-cjk";
Expand All @@ -687,7 +687,10 @@ function splitText(text) {
.forEach((token, index, tokens) => {
// whitespace
if (index % 2 === 1) {
nodes.push({ type: "whitespace", value: " " });
nodes.push({
type: "whitespace",
value: /\n/.test(token) ? "\n" : " "
});
return;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/markdown/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_blockquote/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_break/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_code/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_definition/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_delete/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_emphasis/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_footnote/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_footnoteDefinition/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_footnoteReference/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_heading/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_html/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_ignore/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_image/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_imageReference/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_indentation/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"], { useTabs: true });
run_spec(__dirname, ["markdown"], { proseWrap: "always", useTabs: true });
2 changes: 1 addition & 1 deletion tests/markdown_inlineCode/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
4 changes: 2 additions & 2 deletions tests/markdown_jsx_semi/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
run_spec(__dirname, ["markdown"], { semi: true });
run_spec(__dirname, ["markdown"], { semi: false });
run_spec(__dirname, ["markdown"], { semi: true, proseWrap: "always" });
run_spec(__dirname, ["markdown"], { semi: false, proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_link/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_linkReference/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });
2 changes: 1 addition & 1 deletion tests/markdown_list/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
run_spec(__dirname, ["markdown"]);
run_spec(__dirname, ["markdown"], { proseWrap: "always" });

0 comments on commit 073c0b1

Please sign in to comment.