Skip to content

Commit 640af34

Browse files
committed
work around syntax highlighter stripping leading blank lines
The syntaxhighlighter library strips blank lines at the start of code block it is trying to highlight. In addition to just being wrong, this means that line numbers on the source page will not line up with the real files. Work around this by providing the library with fake objects that ignore the attempt to strip these lines. This uses a fake string and a fake element to hold it. This is an ugly workaround, but allows us to continue using the syntax highlighter via npm.
1 parent 73dc5d1 commit 640af34

File tree

1 file changed

+42
-17
lines changed

1 file changed

+42
-17
lines changed

root/static/js/syntaxhighlighter.mjs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -132,19 +132,16 @@ const processPackages = function(code) {
132132
return code.replace(/(<code class="p(?:er)?l keyword">(use|package|require)<\/code> <code class="p(?:er)?l plain">)([A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*)(.*?<\/code>)/g, replace_pattern);
133133
};
134134

135-
const getCodeLinesHtml = Renderer.prototype.getCodeLinesHtml;
136-
Renderer.prototype.getCodeLinesHtml = function() {
137-
// the syntax highlighter has a bug that strips spaces from the first line.
138-
// replace any leading whitespace with an entity, preventing that.
139-
// html = html.replace(/^ /, "&#32;");
140-
// html = html.replace(/^\t/, "&#9;");
141-
let html = getCodeLinesHtml.apply(this, arguments);
142-
return processPackages.call(this, html);
135+
const processUrls = Renderer.prototype.processUrls;
136+
Renderer.prototype.processUrls = function(html, ...args) {
137+
html = processPackages.apply(this, [ html ]);
138+
html = processUrls.apply(this, [ html, ...args ]);
139+
return html;
143140
};
144141

145142
const getHtml = Renderer.prototype.getHtml;
146-
Renderer.prototype.getHtml = function() {
147-
let html = getHtml.call(this);
143+
Renderer.prototype.getHtml = function(...args) {
144+
let html = getHtml.call(this, ...args);
148145
html = html.replace(/\s+(<(tbody|table|div)\b)/g, '$1');
149146
html = html.replace(/(<\/(tbody|table|div)>)\s+/g, '$1');
150147
return html;
@@ -231,14 +228,42 @@ for (const code of document.querySelectorAll(".content pre > code")) {
231228

232229
config.package_target_type = source ? 'source' : 'pod';
233230

234-
// highlighter strips leading blank lines, throwing off line numbers.
235-
// add a blank line for the highlighter to strip
236-
// const html = code.innerHTML;
237-
// if (html.match(/^ *\n/)) {
238-
// code.innerHTML = "\n " + html;
239-
// }
231+
let highlightObject = code;
232+
233+
const html = code.innerHTML;
234+
if (html.match(/^ *\n+/)) {
235+
// highlighter strips leading blank lines, throwing off line numbers.
236+
// use this awful hack to bypass it. depends on specific details inside
237+
// the syntaxhighlighter module
238+
239+
const fakeCode = {
240+
className: code.className,
241+
id: code.id,
242+
title: code.title,
243+
innerHTML: {
244+
toString: function () { return html },
245+
replace: function (search, replace) {
246+
if (search.toString() == /^[ ]*[\n]+|[\n]*[ ]*$/g.toString()) {
247+
return html.replace(/\n$/g, '');
248+
}
249+
return html.replace(search, replace);
250+
},
251+
},
252+
};
253+
const parentNode = code.parentNode;
254+
fakeCode.parentNode = {
255+
replaceChild: function(newEl, oldEl) {
256+
if (oldEl === fakeCode) {
257+
oldEl = code
258+
}
259+
parentNode.replaceChild(newEl, oldEl);
260+
},
261+
};
262+
263+
highlightObject = fakeCode;
264+
}
240265

241-
SyntaxHighlighter.highlight(config, code);
266+
SyntaxHighlighter.highlight(config, highlightObject);
242267

243268
const pod_lines = pre.dataset.podLines;
244269
if (pod_lines) {

0 commit comments

Comments
 (0)