From cd293fb61a25c81df200d076b0383bc876b84a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Estev=C3=A3o=20Soares=20dos=20Santos?= Date: Mon, 9 May 2022 04:00:29 +0100 Subject: [PATCH] hard line break implementation --- src/subParsers/makehtml/codeSpan.js | 2 ++ src/subParsers/makehtml/emphasisAndStrong.js | 18 +++++++---- src/subParsers/makehtml/githubCodeBlock.js | 1 - src/subParsers/makehtml/hardLineBreaks.js | 32 +++++++++++++++++++ src/subParsers/makehtml/heading.js | 5 ++- src/subParsers/makehtml/spanGamut.js | 12 +------ src/subParsers/makehtml/strikethrough.js | 4 ++- src/subParsers/makehtml/underline.js | 4 ++- .../makehtml/extra.testsuite.commonmark.js | 5 +++ .../functional/makehtml/makehtml.bootstrap.js | 10 ++++-- 10 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 src/subParsers/makehtml/hardLineBreaks.js diff --git a/src/subParsers/makehtml/codeSpan.js b/src/subParsers/makehtml/codeSpan.js index 1c135a3..35d772e 100644 --- a/src/subParsers/makehtml/codeSpan.js +++ b/src/subParsers/makehtml/codeSpan.js @@ -55,6 +55,8 @@ showdown.subParser('makehtml.codeSpan', function (text, options, globals) { c = c.replace(/^([ \t]*)/g, ''); // leading whitespace c = c.replace(/[ \t]*$/g, ''); // trailing whitespace + // remove newlines + c = c.replace(/\n/, ' '); let captureStartEvent = new showdown.Event('makehtml.codeSpan.onCapture', c); captureStartEvent diff --git a/src/subParsers/makehtml/emphasisAndStrong.js b/src/subParsers/makehtml/emphasisAndStrong.js index 73ceff5..c508e92 100644 --- a/src/subParsers/makehtml/emphasisAndStrong.js +++ b/src/subParsers/makehtml/emphasisAndStrong.js @@ -85,18 +85,23 @@ showdown.subParser('makehtml.emphasisAndStrong', function (text, options, global if (showdown.helper.isUndefined(attributes.strong)) { attributes.strong = {}; } + switch (tags) { case '': - otp = '' + txt + ''; + otp = '' + + showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) + + ''; break; case '': - otp = '' + txt + ''; + otp = '' + + showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) + + ''; break; case '': otp = '' + - '' + - txt + - '' + + '' + + showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) + + '' + ''; break; } @@ -109,10 +114,11 @@ showdown.subParser('makehtml.emphasisAndStrong', function (text, options, global ._setOptions(options); beforeHashEvent = globals.converter.dispatch(beforeHashEvent); otp = beforeHashEvent.output; + otp = showdown.subParser('makehtml.hashHTMLSpans')(otp, options, globals); return otp; } - // it's faster to have 3 separate regexes for each case than have just one + // it's faster to have separate regexes for each case than have just one // because of backtracking, in some cases, it could lead to an exponential effect // called "catastrophic backtrace". Ominous! const lmwuStrongEmRegex = /\b___(\S[\s\S]*?)___\b/g, diff --git a/src/subParsers/makehtml/githubCodeBlock.js b/src/subParsers/makehtml/githubCodeBlock.js index ad09aa7..2f1b78d 100644 --- a/src/subParsers/makehtml/githubCodeBlock.js +++ b/src/subParsers/makehtml/githubCodeBlock.js @@ -42,7 +42,6 @@ showdown.subParser('makehtml.githubCodeBlock', function (text, options, globals) }); text = text.replace(emptyBlockRegex, function (wholeMatch, delim, language) { - console.log('|', wholeMatch, '|>'); return parse(emptyBlockRegex, wholeMatch, delim, language, ''); }); diff --git a/src/subParsers/makehtml/hardLineBreaks.js b/src/subParsers/makehtml/hardLineBreaks.js new file mode 100644 index 0000000..e2d27fd --- /dev/null +++ b/src/subParsers/makehtml/hardLineBreaks.js @@ -0,0 +1,32 @@ +//// +// makehtml/emphasisAndStrong.js +// Copyright (c) 2022 ShowdownJS +// +// Transforms MD emphasis and strong into `` and `` html entities +// +// Markdown treats asterisks (*) and underscores (_) as indicators of emphasis. +// Text wrapped with one * or _ will be wrapped with an HTML tag; +// double *’s or _’s will be wrapped with an HTML tag +// +// ***Author:*** +// - Estêvão Soares dos Santos (Tivie) +//// + +showdown.subParser('makehtml.hardLineBreaks', function (text, options) { + + // Do hard breaks + if (options.simpleLineBreaks) { + // GFM style hard breaks + // only add line breaks if the text does not contain a block (special case for lists) + if (!/\n\n¨K/.test(text)) { + text = text.replace(/\n+/gm, '
\n'); + } + } else { + // Vanilla hard breaks + text = text.replace(/ +\n/g, '
\n'); + } + text = text.replace(/\\\n/g, '
\n'); + + return text; + +}); diff --git a/src/subParsers/makehtml/heading.js b/src/subParsers/makehtml/heading.js index 5f81022..9b52d67 100644 --- a/src/subParsers/makehtml/heading.js +++ b/src/subParsers/makehtml/heading.js @@ -168,7 +168,6 @@ showdown.subParser('makehtml.heading', function (text, options, globals) { } nPrepend = showdown.subParser('makehtml.blockGamut')(multilineText, options, globals, 'makehtml.heading'); - //console.log(nPrepend); if (nPrepend !== multilineText) { // we found a block, so it should take precedence prepend += nPrepend; @@ -192,7 +191,7 @@ showdown.subParser('makehtml.heading', function (text, options, globals) { function parseHeader (pattern, wholeMatch, headingText, headingLevel, headingId) { let captureStartEvent = new showdown.Event('makehtml.heading.onCapture', headingText), - otp; + otp; captureStartEvent .setOutput(null) @@ -215,7 +214,7 @@ showdown.subParser('makehtml.heading', function (text, options, globals) { } else { headingText = captureStartEvent.matches.heading; let spanGamut = showdown.subParser('makehtml.spanGamut')(headingText, options, globals), - attributes = captureStartEvent.attributes; + attributes = captureStartEvent.attributes; otp = '' + spanGamut + ''; } diff --git a/src/subParsers/makehtml/spanGamut.js b/src/subParsers/makehtml/spanGamut.js index 794a115..4b1e6f9 100644 --- a/src/subParsers/makehtml/spanGamut.js +++ b/src/subParsers/makehtml/spanGamut.js @@ -34,17 +34,7 @@ showdown.subParser('makehtml.spanGamut', function (text, options, globals) { // now we encode amps and angles text = showdown.subParser('makehtml.encodeAmpsAndAngles')(text, options, globals); - // Do hard breaks - if (options.simpleLineBreaks) { - // GFM style hard breaks - // only add line breaks if the text does not contain a block (special case for lists) - if (!/\n\n¨K/.test(text)) { - text = text.replace(/\n+/g, '
\n'); - } - } else { - // Vanilla hard breaks - text = text.replace(/ +\n/g, '
\n'); - } + text = showdown.subParser('makehtml.hardLineBreaks')(text, options, globals); let afterEvent = new showdown.Event('makehtml.spanGamut.onEnd', text); afterEvent diff --git a/src/subParsers/makehtml/strikethrough.js b/src/subParsers/makehtml/strikethrough.js index ff77503..81c4256 100644 --- a/src/subParsers/makehtml/strikethrough.js +++ b/src/subParsers/makehtml/strikethrough.js @@ -33,7 +33,9 @@ showdown.subParser('makehtml.strikethrough', function (text, options, globals) { if (captureStartEvent.output && captureStartEvent.output !== '') { otp = captureStartEvent.output; } else { - otp = '' + txt + ''; + otp = '' + + showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) + + ''; } let beforeHashEvent = new showdown.Event('makehtml.strikethrough.onHash', otp); diff --git a/src/subParsers/makehtml/underline.js b/src/subParsers/makehtml/underline.js index d223474..df4b785 100644 --- a/src/subParsers/makehtml/underline.js +++ b/src/subParsers/makehtml/underline.js @@ -74,7 +74,9 @@ showdown.subParser('makehtml.underline', function (text, options, globals) { if (captureStartEvent.output && captureStartEvent.output !== '') { otp = captureStartEvent.output; } else { - otp = '' + txt + ''; + otp = '' + + showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) + + ''; } let beforeHashEvent = new showdown.Event('makehtml.underline.onHash', otp); beforeHashEvent diff --git a/test/functional/makehtml/extra.testsuite.commonmark.js b/test/functional/makehtml/extra.testsuite.commonmark.js index 16edca8..b58bfaf 100644 --- a/test/functional/makehtml/extra.testsuite.commonmark.js +++ b/test/functional/makehtml/extra.testsuite.commonmark.js @@ -26,6 +26,7 @@ describe('makeHtml() commonmark testsuite', function () { case 'Thematic breaks_43': // malformed input of test case case 'Thematic breaks_61': // hr inside lists does not make sense case 'Fenced code blocks_146': // as of date, github doesn't support this so we don't either + //case 'Raw HTML_619': // breaks prettifier so the test fails continue; case 'Setext headings_91': //it's failing because the testcase converts " to " even though it's not supposed to @@ -40,6 +41,10 @@ describe('makeHtml() commonmark testsuite', function () { case 'Fenced code blocks_144': // we use different classes to mark languages in fenced code blocks testsuite[section][i].expected = testsuite[section][i].expected.replace('language-;', '; language-;'); break; + + case 'Hard line breaks_638': + console.log(testsuite[section][i].input); + } it(name, assertion(testsuite[section][i], converter, true)); } diff --git a/test/functional/makehtml/makehtml.bootstrap.js b/test/functional/makehtml/makehtml.bootstrap.js index d46298c..ab6f87a 100644 --- a/test/functional/makehtml/makehtml.bootstrap.js +++ b/test/functional/makehtml/makehtml.bootstrap.js @@ -112,8 +112,14 @@ //prettify if (prettify) { - testCase.expected = htmlPrettify(testCase.expected); - testCase.actual = htmlPrettify(testCase.actual); + try { + testCase.expected = htmlPrettify(testCase.expected); + testCase.actual = htmlPrettify(testCase.actual); + } catch (e) { + // some weird html in testcase breaks prettifier so we skip it and do some manual stuff + testCase.expected = testCase.expected.trim().replace('\n', ''); + testCase.actual = testCase.actual.trim().replace('\n', ''); + } }