diff --git a/doc/SETTINGS.md b/doc/SETTINGS.md index 05b9d61e..e0f68191 100644 --- a/doc/SETTINGS.md +++ b/doc/SETTINGS.md @@ -10,8 +10,7 @@ - **codeFontFamily**: The code block font family name. - **lineHeight**: The line height of the editor. - **tabSize**: The number of spaces a tab is equal to. -- **listIndentation**: The list indentation of list items (`"dfm"`, `"tab"` or number `1-4`) - - `tab`: Indent subsequent paragraphs by one tab. +- **listIndentation**: The list indentation of sub list items or paragraphs (`"dfm"`, `"tab"` or number `1-4`) - `dfm`: Each subsequent paragraph in a list item must be indented by either 4 spaces or one tab, we are using 4 spaces (used by Bitbucket and Daring Fireball Markdown Spec). - `number`: Dynamic indent subsequent paragraphs by the given number (1-4) plus list marker width (default). - **autoPairBracket**: If `true` the editor automatically closes brackets. diff --git a/src/main/preference.js b/src/main/preference.js index c7de3ebf..ff4b21eb 100644 --- a/src/main/preference.js +++ b/src/main/preference.js @@ -165,7 +165,7 @@ class Preference { if (settings.listIndentation < 1 || settings.listIndentation > 4) { settings.listIndentation = 1 } - } else if (settings.listIndentation !== 'tab' && settings.listIndentation !== 'dfm') { + } else if (settings.listIndentation !== 'dfm') { settings.listIndentation = 1 } diff --git a/src/muya/lib/index.js b/src/muya/lib/index.js index 0918f5f5..4febf2bd 100644 --- a/src/muya/lib/index.js +++ b/src/muya/lib/index.js @@ -153,7 +153,7 @@ class Muya { if (listIndentation < 1 || listIndentation > 4) { listIndentation = 1 } - } else if (listIndentation !== 'tab' && listIndentation !== 'dfm') { + } else if (listIndentation !== 'dfm') { listIndentation = 1 } this.contentState.listIndentation = listIndentation diff --git a/src/muya/lib/utils/exportMarkdown.js b/src/muya/lib/utils/exportMarkdown.js index 8b1245e3..4044ed14 100644 --- a/src/muya/lib/utils/exportMarkdown.js +++ b/src/muya/lib/utils/exportMarkdown.js @@ -16,18 +16,13 @@ class ExportMarkdown { this.isLooseParentList = true // set and validate settings - if (listIndentation === 'tab') { - this.listIndentation = '\t' - this.listIndentationCount = null - } else if (listIndentation === 'dfm') { - // static 4 spaces - this.listIndentation = ' ' - this.listIndentationCount = null + this.listIndentation = 'number' + if (listIndentation === 'dfm') { + this.listIndentation = 'dfm' + this.listIndentationCount = 4 } else if (typeof listIndentation === 'number') { - this.listIndentation = null this.listIndentationCount = Math.min(Math.max(listIndentation, 1), 4) } else { - this.listIndentation = null this.listIndentationCount = 1 } } @@ -36,7 +31,7 @@ class ExportMarkdown { return this.translateBlocks2Markdown(this.blocks) } - translateBlocks2Markdown (blocks, indent = '') { + translateBlocks2Markdown (blocks, indent = '', listIndent = '') { const result = [] // helper for CommonMark 264 let lastListBullet = '' @@ -105,7 +100,7 @@ class ExportMarkdown { if (insertNewLine) { this.insertLineBreak(result, indent) } - result.push(this.normalizeListItem(block, indent)) + result.push(this.normalizeListItem(block, indent + listIndent)) this.isLooseParentList = true break } @@ -124,7 +119,7 @@ class ExportMarkdown { } this.listType.push({ type: 'ul' }) - result.push(this.normalizeList(block, indent)) + result.push(this.normalizeList(block, indent, listIndent)) this.listType.pop() break } @@ -143,7 +138,7 @@ class ExportMarkdown { } const listCount = block.start !== undefined ? block.start : 1 this.listType.push({ type: 'ol', listCount }) - result.push(this.normalizeList(block, indent)) + result.push(this.normalizeList(block, indent, listIndent)) this.listType.pop() break } @@ -309,9 +304,9 @@ class ExportMarkdown { return result.join('\n') + '\n' } - normalizeList (block, indent) { + normalizeList (block, indent, listIndent) { const { children } = block - return this.translateBlocks2Markdown(children, indent) + return this.translateBlocks2Markdown(children, indent, listIndent) } normalizeListItem (block, indent) { @@ -324,13 +319,34 @@ class ExportMarkdown { if (isUnorderedList) { itemMarker = bulletMarkerOrDelimiter ? `${bulletMarkerOrDelimiter} ` : '- ' } else { + // NOTE: GitHub and Bitbucket limit the list count to 99 but this is nowhere defined. + // We limit the number to 99 for Daring Fireball Markdown to prevent indentation issues. + let n = listInfo.listCount + if ((this.listIndentation === 'dfm' && n > 99) || n > 999999999) { + n = 1 + } + listInfo.listCount++ + const delimiter = bulletMarkerOrDelimiter ? bulletMarkerOrDelimiter : '.' - itemMarker = `${listInfo.listCount++}${delimiter} ` + itemMarker = `${n}${delimiter} ` } - // We already added one space to the indentation - const listIndent = this.getListIndentation(itemMarker.length - 1) - const newIndent = indent + listIndent + // Subsequent paragraph indentation + const newIndent = indent + ' '.repeat(itemMarker.length) + + // New list indentation. We already added one space to the indentation + let listIndent = '' + const { listIndentation } = this + if (listIndentation === 'dfm') { + listIndent = ' '.repeat(4 - itemMarker.length) + } else if (listIndentation === 'number') { + listIndent = ' '.repeat(this.listIndentationCount - 1) + } + + // TODO: Indent subsequent paragraphs by one tab. - not important + // Problem: "translateBlocks2Markdown" use "indent" in spaces to indent elements. How should + // we integrate tabs in blockquotes and subsequent paragraphs and how to combine with spaces? + // I don't know how to combine tabs and spaces and it seems not specified, so work for another day. if (isUnorderedList && block.listItemType === 'task') { const firstChild = children[0] @@ -339,23 +355,9 @@ class ExportMarkdown { } result.push(`${indent}${itemMarker}`) - result.push(this.translateBlocks2Markdown(children, newIndent).substring(newIndent.length)) + result.push(this.translateBlocks2Markdown(children, newIndent, listIndent).substring(newIndent.length)) return result.join('') } - - getListIndentation (listMarkerWidth) { - // listIndentation: - // tab: Indent subsequent paragraphs by one tab. - // dfm: Each subsequent paragraph in a list item must be indented by either 4 spaces or one tab (used by Bitbucket and Daring Fireball). - // number: Dynamic indent subsequent paragraphs by the given number (1-4) plus list marker width. - - if (this.listIndentation) { - return this.listIndentation - } else if (this.listIndentationCount) { - return ' '.repeat(listMarkerWidth + this.listIndentationCount) - } - return ' '.repeat(listMarkerWidth) - } } export default ExportMarkdown diff --git a/test/unit/specs/markdown-list-indentation.spec.js b/test/unit/specs/markdown-list-indentation.spec.js index 6bdbeb5e..1fe98ef6 100644 --- a/test/unit/specs/markdown-list-indentation.spec.js +++ b/test/unit/specs/markdown-list-indentation.spec.js @@ -15,8 +15,9 @@ const createMuyaContext = listIdentation => { // Muya parser (Markdown to HTML to Markdown) // -const verifyMarkdown = (expectedMarkdown, listIdentation) => { - const markdown = `start +const verifyMarkdown = (expectedMarkdown, listIdentation, markdown = '') => { + if (!markdown) { + markdown = `start - foo - foo @@ -41,6 +42,7 @@ sep 141. foo 1. foo ` + } const ctx = createMuyaContext(listIdentation) ctx.contentState.importMarkdown(markdown) @@ -50,7 +52,7 @@ sep expect(exportedMarkdown).to.equal(expectedMarkdown) } -describe('Muya tab identation', () => { +describe('Muya list identation', () => { it('Indent by 1 space', () => { const md = `start @@ -164,7 +166,7 @@ sep verifyMarkdown(md, 4) }) - it('Indent by one tab', () => { +/* it('Indent by one tab', () => { const md = `start - foo @@ -191,7 +193,7 @@ sep \t\t\t1. foo ` verifyMarkdown(md, "tab") - }) + })*/ it('Indent using Daring Fireball Markdown Spec', () => { const md = `start @@ -215,9 +217,10 @@ sep 3. foo 3. foo 20. foo - 141. foo + 99. foo 1. foo ` - verifyMarkdown(md, "dfm") + + verifyMarkdown(md, "dfm", md) }) })