diff --git a/src/test/suite/integration/toc.test.ts b/src/test/suite/integration/toc.test.ts index 506bae84..cdd7cfa3 100644 --- a/src/test/suite/integration/toc.test.ts +++ b/src/test/suite/integration/toc.test.ts @@ -206,6 +206,59 @@ suite("TOC.", () => { }); + test("Ordered list (list markers larger than 9)", async () => { + await updateConfiguration({ config: [["markdown.extension.toc.orderedList", true]] }); + await testCommand('markdown.extension.toc.create', + [ + '# H1', + '# H2', + '# H3', + '# H4', + '# H5', + '# H6', + '# H7', + '# H8', + '# H9', + '# H10', + '## H11', + '### H12', + '', + '' + ], + new Selection(13, 0, 13, 0), + [ + '# H1', + '# H2', + '# H3', + '# H4', + '# H5', + '# H6', + '# H7', + '# H8', + '# H9', + '# H10', + '## H11', + '### H12', + '', + '1. [H1](#h1)', + '2. [H2](#h2)', + '3. [H3](#h3)', + '4. [H4](#h4)', + '5. [H5](#h5)', + '6. [H6](#h6)', + '7. [H7](#h7)', + '8. [H8](#h8)', + '9. [H9](#h9)', + '10. [H10](#h10)', + ' 1. [H11](#h11)', + ' 1. [H12](#h12)', + '' + ], + new Selection(25, 0, 25, 0) + ); + await resetConfiguration(); + }); + test("Setext headings", () => { return testCommand('markdown.extension.toc.create', [ diff --git a/src/toc.ts b/src/toc.ts index 6c090f11..368c48ea 100644 --- a/src/toc.ts +++ b/src/toc.ts @@ -263,19 +263,28 @@ async function generateTocText(doc: TextDocument): Promise { // The actual level range of a document can be smaller than settings. So we need to calculate the real start level. const startDepth = Math.max(tocConfig.startDepth, Math.min(...tocEntries.map(h => h.level))); - const order: number[] = new Array(tocConfig.endDepth - startDepth + 1).fill(0); // Used for ordered list + // Order counter for each heading level (from startDepth to endDepth), used only for ordered list + const orderCounter: number[] = new Array(tocConfig.endDepth - startDepth + 1).fill(0); tocEntries.forEach(entry => { const relativeLevel = entry.level - startDepth; + const currHeadingOrder = ++orderCounter[relativeLevel]; + let indentationFix = ''; + if (tocConfig.orderedList) { + const shift = orderCounter.slice(0, relativeLevel).map(c => String(c).length - 1).reduce((a, b) => a + b, 0); + indentationFix = ' '.repeat(shift); + } const row = [ - docConfig.tab.repeat(relativeLevel), - (tocConfig.orderedList ? (orderedListMarkerIsOne ? '1' : ++order[relativeLevel]) + '.' : tocConfig.listMarker) + ' ', + docConfig.tab.repeat(relativeLevel) + indentationFix, + (tocConfig.orderedList ? (orderedListMarkerIsOne ? '1' : currHeadingOrder) + '.' : tocConfig.listMarker) + ' ', tocConfig.plaintext ? entry.visibleText : `[${entry.visibleText}](#${entry.slug})` ]; toc.push(row.join('')); + + // Reset order counter for its sub-headings if (tocConfig.orderedList) { - order.fill(0, relativeLevel + 1); + orderCounter.fill(0, relativeLevel + 1); } }); while (/^[ \t]/.test(toc[0])) {