hard line break implementation

This commit is contained in:
Estevão Soares dos Santos 2022-05-09 04:00:29 +01:00
parent 6e6af3cc03
commit cd293fb61a
10 changed files with 68 additions and 25 deletions

View File

@ -55,6 +55,8 @@ showdown.subParser('makehtml.codeSpan', function (text, options, globals) {
c = c.replace(/^([ \t]*)/g, ''); // leading whitespace c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
c = c.replace(/[ \t]*$/g, ''); // trailing whitespace c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
// remove newlines
c = c.replace(/\n/, ' ');
let captureStartEvent = new showdown.Event('makehtml.codeSpan.onCapture', c); let captureStartEvent = new showdown.Event('makehtml.codeSpan.onCapture', c);
captureStartEvent captureStartEvent

View File

@ -85,18 +85,23 @@ showdown.subParser('makehtml.emphasisAndStrong', function (text, options, global
if (showdown.helper.isUndefined(attributes.strong)) { if (showdown.helper.isUndefined(attributes.strong)) {
attributes.strong = {}; attributes.strong = {};
} }
switch (tags) { switch (tags) {
case '<em>': case '<em>':
otp = '<em' + showdown.helper._populateAttributes(attributes.em) + '>' + txt + '</em>'; otp = '<em' + showdown.helper._populateAttributes(attributes.em) + '>' +
showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) +
'</em>';
break; break;
case '<strong>': case '<strong>':
otp = '<strong' + showdown.helper._populateAttributes(attributes.strong) + '>' + txt + '</strong>'; otp = '<strong' + showdown.helper._populateAttributes(attributes.strong) + '>' +
showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) +
'</strong>';
break; break;
case '<strong><em>': case '<strong><em>':
otp = '<strong' + showdown.helper._populateAttributes(attributes.strong) + '>' + otp = '<strong' + showdown.helper._populateAttributes(attributes.strong) + '>' +
'<em' + showdown.helper._populateAttributes(attributes.em) + '>' + '<em' + showdown.helper._populateAttributes(attributes.em) + '>' +
txt + showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) +
'</em>' + '</em>' +
'</strong>'; '</strong>';
break; break;
} }
@ -109,10 +114,11 @@ showdown.subParser('makehtml.emphasisAndStrong', function (text, options, global
._setOptions(options); ._setOptions(options);
beforeHashEvent = globals.converter.dispatch(beforeHashEvent); beforeHashEvent = globals.converter.dispatch(beforeHashEvent);
otp = beforeHashEvent.output; otp = beforeHashEvent.output;
otp = showdown.subParser('makehtml.hashHTMLSpans')(otp, options, globals);
return otp; 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 // because of backtracking, in some cases, it could lead to an exponential effect
// called "catastrophic backtrace". Ominous! // called "catastrophic backtrace". Ominous!
const lmwuStrongEmRegex = /\b___(\S[\s\S]*?)___\b/g, const lmwuStrongEmRegex = /\b___(\S[\s\S]*?)___\b/g,

View File

@ -42,7 +42,6 @@ showdown.subParser('makehtml.githubCodeBlock', function (text, options, globals)
}); });
text = text.replace(emptyBlockRegex, function (wholeMatch, delim, language) { text = text.replace(emptyBlockRegex, function (wholeMatch, delim, language) {
console.log('|', wholeMatch, '|>');
return parse(emptyBlockRegex, wholeMatch, delim, language, ''); return parse(emptyBlockRegex, wholeMatch, delim, language, '');
}); });

View File

@ -0,0 +1,32 @@
////
// makehtml/emphasisAndStrong.js
// Copyright (c) 2022 ShowdownJS
//
// Transforms MD emphasis and strong into `<em>` and `<strong>` html entities
//
// Markdown treats asterisks (*) and underscores (_) as indicators of emphasis.
// Text wrapped with one * or _ will be wrapped with an HTML <em> tag;
// double *s or _s will be wrapped with an HTML <strong> tag
//
// ***Author:***
// - Estêvão Soares dos Santos (Tivie) <https://github.com/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, '<br />\n');
}
} else {
// Vanilla hard breaks
text = text.replace(/ +\n/g, '<br />\n');
}
text = text.replace(/\\\n/g, '<br />\n');
return text;
});

View File

@ -168,7 +168,6 @@ showdown.subParser('makehtml.heading', function (text, options, globals) {
} }
nPrepend = showdown.subParser('makehtml.blockGamut')(multilineText, options, globals, 'makehtml.heading'); nPrepend = showdown.subParser('makehtml.blockGamut')(multilineText, options, globals, 'makehtml.heading');
//console.log(nPrepend);
if (nPrepend !== multilineText) { if (nPrepend !== multilineText) {
// we found a block, so it should take precedence // we found a block, so it should take precedence
prepend += nPrepend; prepend += nPrepend;
@ -192,7 +191,7 @@ showdown.subParser('makehtml.heading', function (text, options, globals) {
function parseHeader (pattern, wholeMatch, headingText, headingLevel, headingId) { function parseHeader (pattern, wholeMatch, headingText, headingLevel, headingId) {
let captureStartEvent = new showdown.Event('makehtml.heading.onCapture', headingText), let captureStartEvent = new showdown.Event('makehtml.heading.onCapture', headingText),
otp; otp;
captureStartEvent captureStartEvent
.setOutput(null) .setOutput(null)
@ -215,7 +214,7 @@ showdown.subParser('makehtml.heading', function (text, options, globals) {
} else { } else {
headingText = captureStartEvent.matches.heading; headingText = captureStartEvent.matches.heading;
let spanGamut = showdown.subParser('makehtml.spanGamut')(headingText, options, globals), let spanGamut = showdown.subParser('makehtml.spanGamut')(headingText, options, globals),
attributes = captureStartEvent.attributes; attributes = captureStartEvent.attributes;
otp = '<h' + headingLevel + showdown.helper._populateAttributes(attributes) + '>' + spanGamut + '</h' + headingLevel + '>'; otp = '<h' + headingLevel + showdown.helper._populateAttributes(attributes) + '>' + spanGamut + '</h' + headingLevel + '>';
} }

View File

@ -34,17 +34,7 @@ showdown.subParser('makehtml.spanGamut', function (text, options, globals) {
// now we encode amps and angles // now we encode amps and angles
text = showdown.subParser('makehtml.encodeAmpsAndAngles')(text, options, globals); text = showdown.subParser('makehtml.encodeAmpsAndAngles')(text, options, globals);
// Do hard breaks text = showdown.subParser('makehtml.hardLineBreaks')(text, options, globals);
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, '<br />\n');
}
} else {
// Vanilla hard breaks
text = text.replace(/ +\n/g, '<br />\n');
}
let afterEvent = new showdown.Event('makehtml.spanGamut.onEnd', text); let afterEvent = new showdown.Event('makehtml.spanGamut.onEnd', text);
afterEvent afterEvent

View File

@ -33,7 +33,9 @@ showdown.subParser('makehtml.strikethrough', function (text, options, globals) {
if (captureStartEvent.output && captureStartEvent.output !== '') { if (captureStartEvent.output && captureStartEvent.output !== '') {
otp = captureStartEvent.output; otp = captureStartEvent.output;
} else { } else {
otp = '<del' + showdown.helper._populateAttributes(captureStartEvent.attributes) + '>' + txt + '</del>'; otp = '<del' + showdown.helper._populateAttributes(captureStartEvent.attributes) + '>' +
showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) +
'</del>';
} }
let beforeHashEvent = new showdown.Event('makehtml.strikethrough.onHash', otp); let beforeHashEvent = new showdown.Event('makehtml.strikethrough.onHash', otp);

View File

@ -74,7 +74,9 @@ showdown.subParser('makehtml.underline', function (text, options, globals) {
if (captureStartEvent.output && captureStartEvent.output !== '') { if (captureStartEvent.output && captureStartEvent.output !== '') {
otp = captureStartEvent.output; otp = captureStartEvent.output;
} else { } else {
otp = '<u' + showdown.helper._populateAttributes(captureStartEvent.attributes) + '>' + txt + '</u>'; otp = '<u' + showdown.helper._populateAttributes(captureStartEvent.attributes) + '>' +
showdown.subParser('makehtml.hardLineBreaks')(txt, options, globals) +
'</u>';
} }
let beforeHashEvent = new showdown.Event('makehtml.underline.onHash', otp); let beforeHashEvent = new showdown.Event('makehtml.underline.onHash', otp);
beforeHashEvent beforeHashEvent

View File

@ -26,6 +26,7 @@ describe('makeHtml() commonmark testsuite', function () {
case 'Thematic breaks_43': // malformed input of test case case 'Thematic breaks_43': // malformed input of test case
case 'Thematic breaks_61': // hr inside lists does not make sense 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 '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; continue;
case 'Setext headings_91': //it's failing because the testcase converts " to &quot; even though it's not supposed to case 'Setext headings_91': //it's failing because the testcase converts " to &quot; 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 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-;'); testsuite[section][i].expected = testsuite[section][i].expected.replace('language-;', '; language-;');
break; break;
case 'Hard line breaks_638':
console.log(testsuite[section][i].input);
} }
it(name, assertion(testsuite[section][i], converter, true)); it(name, assertion(testsuite[section][i], converter, true));
} }

View File

@ -112,8 +112,14 @@
//prettify //prettify
if (prettify) { if (prettify) {
testCase.expected = htmlPrettify(testCase.expected); try {
testCase.actual = htmlPrettify(testCase.actual); 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', '');
}
} }