diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 7b5a8f5b..764e3973 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -41,3 +41,33 @@ Examples: ``` --> + +- Markdown: Do not align table contents if it exceeds the print width and `--prose-wrap never` is set ([#5701] by [@chenshuai2144]) + + The aligned table is less readable than the compact one + if it's particularly long and the word wrapping is not enabled in the editor + so we now print them as compact tables in these situations. + + + ```md + + | Property | Description | Type | Default | + | -------- | ----------- | ---- | ------- | + | bordered | Toggles rendering of the border around the list | boolean | false | + | itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - | + + + | Property | Description | Type | Default | + | ---------- | --------------------------------------------------------------------------------------------------------------------- | ------- | ------- | + | bordered | Toggles rendering of the border around the list | boolean | false | + | itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - | + + + | Property | Description | Type | Default | + | --- | --- | --- | --- | + | bordered | Toggles rendering of the border around the list | boolean | false | + | itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - | + ``` + +[@chenshuai2144]: https://github.com/chenshuai2144 +[#5701]: https://github.com/prettier/prettier/pull/5701 diff --git a/src/language-markdown/printer-markdown.js b/src/language-markdown/printer-markdown.js index 40f03656..9b7ba4b8 100644 --- a/src/language-markdown/printer-markdown.js +++ b/src/language-markdown/printer-markdown.js @@ -6,6 +6,7 @@ const pragma = require("./pragma"); const preprocess = require("./preprocess"); const { builders: { + breakParent, concat, join, line, @@ -13,6 +14,7 @@ const { markAsRoot, hardline, softline, + ifBreak, fill, align, indent, @@ -509,6 +511,7 @@ function printLine(path, value, options) { } function printTable(path, options, print) { + const hardlineWithoutBreakParent = hardline.parts[0]; const node = path.getValue(); const contents = []; // { [rowIndex: number]: { [columnIndex: number]: string } } @@ -524,6 +527,7 @@ function printTable(path, options, print) { contents.push(rowContents); }, "children"); + // Get the width of each column const columnMaxWidths = contents.reduce( (currentWidths, rowContents) => currentWidths.map((width, columnIndex) => @@ -531,28 +535,49 @@ function printTable(path, options, print) { ), contents[0].map(() => 3) // minimum width = 3 (---, :--, :-:, --:) ); - - return join(hardline, [ + const alignedTable = join(hardlineWithoutBreakParent, [ printRow(contents[0]), printSeparator(), - join(hardline, contents.slice(1).map(printRow)) + join( + hardlineWithoutBreakParent, + contents.slice(1).map(rowContents => printRow(rowContents)) + ) ]); - function printSeparator() { + if (options.proseWrap !== "never") { + return concat([breakParent, alignedTable]); + } + + // Only if the --prose-wrap never is set and it exceeds the print width. + const compactTable = join(hardlineWithoutBreakParent, [ + printRow(contents[0], /* isCompact */ true), + printSeparator(/* isCompact */ true), + join( + hardlineWithoutBreakParent, + contents + .slice(1) + .map(rowContents => printRow(rowContents, /* isCompact */ true)) + ) + ]); + + return concat([breakParent, group(ifBreak(compactTable, alignedTable))]); + + function printSeparator(isCompact) { return concat([ "| ", join( " | ", columnMaxWidths.map((width, index) => { + const spaces = isCompact ? 3 : width; switch (node.align[index]) { case "left": - return ":" + "-".repeat(width - 1); + return ":" + "-".repeat(spaces - 1); case "right": - return "-".repeat(width - 1) + ":"; + return "-".repeat(spaces - 1) + ":"; case "center": - return ":" + "-".repeat(width - 2) + ":"; + return ":" + "-".repeat(spaces - 2) + ":"; default: - return "-".repeat(width); + return "-".repeat(spaces); } }) ), @@ -560,32 +585,36 @@ function printTable(path, options, print) { ]); } - function printRow(rowContents) { + function printRow(rowContents, isCompact) { return concat([ "| ", join( " | ", - rowContents.map((rowContent, columnIndex) => { - switch (node.align[columnIndex]) { - case "right": - return alignRight(rowContent, columnMaxWidths[columnIndex]); - case "center": - return alignCenter(rowContent, columnMaxWidths[columnIndex]); - default: - return alignLeft(rowContent, columnMaxWidths[columnIndex]); - } - }) + isCompact + ? rowContents + : rowContents.map((rowContent, columnIndex) => { + switch (node.align[columnIndex]) { + case "right": + return alignRight(rowContent, columnMaxWidths[columnIndex]); + case "center": + return alignCenter(rowContent, columnMaxWidths[columnIndex]); + default: + return alignLeft(rowContent, columnMaxWidths[columnIndex]); + } + }) ), " |" ]); } function alignLeft(text, width) { - return concat([text, " ".repeat(width - privateUtil.getStringWidth(text))]); + const spaces = width - privateUtil.getStringWidth(text); + return concat([text, " ".repeat(spaces)]); } function alignRight(text, width) { - return concat([" ".repeat(width - privateUtil.getStringWidth(text)), text]); + const spaces = width - privateUtil.getStringWidth(text); + return concat([" ".repeat(spaces), text]); } function alignCenter(text, width) { diff --git a/tests/markdown_long_table/__snapshots__/jsfmt.spec.js.snap b/tests/markdown_long_table/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 00000000..1b3fe4c5 --- /dev/null +++ b/tests/markdown_long_table/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,76 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`long-table.md 1`] = ` +====================================options===================================== +parsers: ["markdown"] +printWidth: 80 + | printWidth +=====================================input====================================== +| Property | Description | Type | Default | +| -------- | ----------- | ---- | ------- | +| bordered | Toggles rendering of the border around the list | boolean | false | +| footer | List footer renderer | string\\|ReactNode | - | +| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - | +| header | List header renderer | string\\|ReactNode | - | +| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string | - | +| rowKey | Item's unique key, could be a string or function that returns a string | string\\|Function(record):string | \`key\` | +| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false | +| loadMore | Shows a load more content | string\\|ReactNode | - | +| locale | i18n text including empty text | object | emptyText: 'No Data'
| +| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \\| object | false | +| split | Toggles rendering of the split under the list item | boolean | true | +=====================================output===================================== +| Property | Description | Type | Default | +| ---------- | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------- | +| bordered | Toggles rendering of the border around the list | boolean | false | +| footer | List footer renderer | string\\|ReactNode | - | +| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - | +| header | List header renderer | string\\|ReactNode | - | +| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string | - | +| rowKey | Item's unique key, could be a string or function that returns a string | string\\|Function(record):string | \`key\` | +| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false | +| loadMore | Shows a load more content | string\\|ReactNode | - | +| locale | i18n text including empty text | object | emptyText: 'No Data'
| +| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \\| object | false | +| split | Toggles rendering of the split under the list item | boolean | true | + +================================================================================ +`; + +exports[`long-table.md 2`] = ` +====================================options===================================== +parsers: ["markdown"] +printWidth: 80 +proseWrap: "never" + | printWidth +=====================================input====================================== +| Property | Description | Type | Default | +| -------- | ----------- | ---- | ------- | +| bordered | Toggles rendering of the border around the list | boolean | false | +| footer | List footer renderer | string\\|ReactNode | - | +| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - | +| header | List header renderer | string\\|ReactNode | - | +| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string | - | +| rowKey | Item's unique key, could be a string or function that returns a string | string\\|Function(record):string | \`key\` | +| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false | +| loadMore | Shows a load more content | string\\|ReactNode | - | +| locale | i18n text including empty text | object | emptyText: 'No Data'
| +| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \\| object | false | +| split | Toggles rendering of the split under the list item | boolean | true | +=====================================output===================================== +| Property | Description | Type | Default | +| --- | --- | --- | --- | +| bordered | Toggles rendering of the border around the list | boolean | false | +| footer | List footer renderer | string\\|ReactNode | - | +| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - | +| header | List header renderer | string\\|ReactNode | - | +| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string | - | +| rowKey | Item's unique key, could be a string or function that returns a string | string\\|Function(record):string | \`key\` | +| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false | +| loadMore | Shows a load more content | string\\|ReactNode | - | +| locale | i18n text including empty text | object | emptyText: 'No Data'
| +| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \\| object | false | +| split | Toggles rendering of the split under the list item | boolean | true | + +================================================================================ +`; diff --git a/tests/markdown_long_table/jsfmt.spec.js b/tests/markdown_long_table/jsfmt.spec.js new file mode 100644 index 00000000..e1c94789 --- /dev/null +++ b/tests/markdown_long_table/jsfmt.spec.js @@ -0,0 +1,2 @@ +run_spec(__dirname, ["markdown"]); +run_spec(__dirname, ["markdown"], { proseWrap: "never" }); diff --git a/tests/markdown_long_table/long-table.md b/tests/markdown_long_table/long-table.md new file mode 100644 index 00000000..57ff8ab2 --- /dev/null +++ b/tests/markdown_long_table/long-table.md @@ -0,0 +1,13 @@ +| Property | Description | Type | Default | +| -------- | ----------- | ---- | ------- | +| bordered | Toggles rendering of the border around the list | boolean | false | +| footer | List footer renderer | string\|ReactNode | - | +| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - | +| header | List header renderer | string\|ReactNode | - | +| itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - | +| rowKey | Item's unique key, could be a string or function that returns a string | string\|Function(record):string | `key` | +| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false | +| loadMore | Shows a load more content | string\|ReactNode | - | +| locale | i18n text including empty text | object | emptyText: 'No Data'
| +| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \| object | false | +| split | Toggles rendering of the split under the list item | boolean | true | \ No newline at end of file diff --git a/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap b/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap index e4eb22d7..aa3638a5 100644 --- a/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap +++ b/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap @@ -134,3 +134,45 @@ proseWrap: "always" ================================================================================ `; + +exports[`table.md 1`] = ` +====================================options===================================== +parsers: ["markdown"] +printWidth: 80 +proseWrap: "always" + | printWidth +=====================================input====================================== +- min-table + + | Age | Time | Food | Gold | Requirement | + | ------------ | ----- | ---- | ---- | ----------------------- | + | Feudal Age | 02:10 | 500 | 0 | Dark Age building x 2 | + | Castle Age | 02:40 | 800 | 200 |- | + | Imperial Age | 03:30 | 1000 | 800 | Castle Age building x 2 | +- big-table + + |学号|姓名|分数| + |-|-|-| + |小明|男|75| + |小红|女|79| + |小陆|男|92| + +=====================================output===================================== +- min-table + + | Age | Time | Food | Gold | Requirement | + | ------------ | ----- | ---- | ---- | ----------------------- | + | Feudal Age | 02:10 | 500 | 0 | Dark Age building x 2 | + | Castle Age | 02:40 | 800 | 200 | - | + | Imperial Age | 03:30 | 1000 | 800 | Castle Age building x 2 | + +- big-table + + | 学号 | 姓名 | 分数 | + | ---- | ---- | ---- | + | 小明 | 男 | 75 | + | 小红 | 女 | 79 | + | 小陆 | 男 | 92 | + +================================================================================ +`; diff --git a/tests/markdown_table/table.md b/tests/markdown_table/table.md new file mode 100644 index 00000000..2096adf1 --- /dev/null +++ b/tests/markdown_table/table.md @@ -0,0 +1,14 @@ +- min-table + + | Age | Time | Food | Gold | Requirement | + | ------------ | ----- | ---- | ---- | ----------------------- | + | Feudal Age | 02:10 | 500 | 0 | Dark Age building x 2 | + | Castle Age | 02:40 | 800 | 200 |- | + | Imperial Age | 03:30 | 1000 | 800 | Castle Age building x 2 | +- big-table + + |学号|姓名|分数| + |-|-|-| + |小明|男|75| + |小红|女|79| + |小陆|男|92|