diff --git a/docs/userGuide/syntax/code.mbdf b/docs/userGuide/syntax/code.mbdf index e4aaef01f2..9f9278ce3e 100644 --- a/docs/userGuide/syntax/code.mbdf +++ b/docs/userGuide/syntax/code.mbdf @@ -38,7 +38,7 @@ To enable syntax coloring, specify a language next to the backticks before the f ##### Line numbering -Line numbers are automatically provided by default. To hide line numbers, add the class `no-line-numbers ` to the code block as below +Line numbers are provided by default. To hide line numbers, add the class `no-line-numbers` to the code block as below @@ -61,6 +61,30 @@ Line numbers are automatically provided by default. To hide line numbers, add th +You can have your line numbers start with a value other than `1` with the `start-from` attribute. + + + + +```` {.no-line-numbers} +```js {start-from=6} +function add(a, b) { + return a + b; +} +``` +```` + + + +```js {start-from=6} +function add(a, b) { + return a + b; +} +``` + + + + ##### Line highlighting To highlight lines, add the attribute `highlight-lines` with the line numbers as value, as shown below. You can specify ranges or individual line numbers. diff --git a/src/lib/markbind/src/lib/markdown-it/index.js b/src/lib/markbind/src/lib/markdown-it/index.js index d89a5e31cb..1ecc0f6c09 100644 --- a/src/lib/markbind/src/lib/markdown-it/index.js +++ b/src/lib/markbind/src/lib/markdown-it/index.js @@ -30,6 +30,18 @@ markdownIt.renderer.rules.table_close = (tokens, idx) => { return ''; }; +function getAttributeAndDelete(token, attr) { + const index = token.attrIndex(attr); + if (index === -1) { + return undefined; + } + // tokens are stored as an array of two-element-arrays: + // e.g. [ ['highlight-lines', '1,2,3'], ['start-from', '1'] ] + const value = token.attrs[index][1]; + token.attrs.splice(index, 1); + return value; +} + // syntax highlight code fences and add line numbers markdownIt.renderer.rules.fence = (tokens, idx, options, env, slf) => { const token = tokens[idx]; @@ -64,18 +76,31 @@ markdownIt.renderer.rules.fence = (tokens, idx, options, env, slf) => { if (!highlighted) { lines = markdownIt.utils.escapeHtml(str).split('\n'); } + + const startFromOneBased = Math.max(1, parseInt(getAttributeAndDelete(token, 'start-from'), 10) || 1); + const startFromZeroBased = startFromOneBased - 1; + + if (startFromOneBased > 1) { + // counter is incremented on each span, so we need to subtract 1 + token.attrJoin('style', `counter-reset: line ${startFromZeroBased};`); + } - const highlightLinesInput = token.attrGet('highlight-lines'); + const highlightLinesInput = getAttributeAndDelete(token, 'highlight-lines'); let lineNumbersAndRanges = []; if (highlightLinesInput) { // example input format: "1,4-7,8,11-55" // output: [[1],[4,7],[8],[11,55]] // the output is an array contaning either single line numbers [lineNum] or ranges [start, end] // ',' delimits either single line numbers (eg: 1) or ranges (eg: 4-7) - highlightLines = highlightLinesInput.split(','); + const highlightLines = highlightLinesInput.split(','); // if it's the single number, it will just be parsed as an int, (eg: ['1'] --> [1] ) // if it's a range, it will be parsed as as an array of two ints (eg: ['4-7'] --> [4,6]) - lineNumbersAndRanges = highlightLines.map(elem => elem.split('-').map(lineNumber => parseInt(lineNumber, 10))); + function parseAndZeroBaseLineNumber(numberString) { + // authors provide line numbers to highlight based on the 'start-from' attribute if it exists + // so we need to shift them all back down to start at 0 + return parseInt(numberString, 10) - startFromZeroBased; + } + lineNumbersAndRanges = highlightLines.map(elem => elem.split('-').map(parseAndZeroBaseLineNumber)); } lines.pop(); // last line is always a single '\n' newline, so we remove it diff --git a/test/functional/test_site/expected/testCodeBlocks.html b/test/functional/test_site/expected/testCodeBlocks.html index 46309043f9..46a7829fc7 100644 --- a/test/functional/test_site/expected/testCodeBlocks.html +++ b/test/functional/test_site/expected/testCodeBlocks.html @@ -32,6 +32,12 @@
function fourEmptyLinesBelow() {} // four empty lines above

hljs span spanning multiple lines

*****-----
+

start-from attr causes inline style to be set

+
*****-----
+

highlight-lines attr causes corresponding lines to have 'highlighted' class

+
1  highlighted23  highlighted45  highlighted6  highlighted7  highlighted8  highlighted910
+

highlight-lines attr with start-from attr cause corresponding lines to have 'highlighted' class based on 'start-from'

+
11  highlighted1213  highlighted1415  highlighted16  highlighted17  highlighted18  highlighted1920