Skip to content

Commit 253ef1f

Browse files
LeoMcAfiji-flo
andauthored
feat(syntax-highlight): do client side, support more languages (#11654)
Co-authored-by: Florian Dieminger <[email protected]>
1 parent 6b75edd commit 253ef1f

File tree

12 files changed

+247
-176
lines changed

12 files changed

+247
-176
lines changed

Diff for: build/blog.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
postProcessSmallerHeadingIDs,
2929
} from "./utils.js";
3030
import { slugToFolder } from "../libs/slug-utils/index.js";
31-
import { syntaxHighlight } from "./syntax-highlight.js";
31+
import { wrapCodeExamples } from "./code-headers.js";
3232
import { wrapTables } from "./wrap-tables.js";
3333
import { Doc } from "../libs/types/document.js";
3434
import { extractSections } from "./extract-sections.js";
@@ -391,7 +391,7 @@ export async function buildPost(
391391
doc.hasMathML = true;
392392
}
393393
$("div.hidden").remove();
394-
syntaxHighlight($, doc);
394+
wrapCodeExamples($);
395395
injectNoTranslate($);
396396
injectLoadingLazyAttributes($);
397397
postProcessExternalLinks($);

Diff for: build/code-headers.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as cheerio from "cheerio";
2+
3+
// Over the years we have accumulated some weird <pre> tags whose
4+
// brush is more or less "junk".
5+
// TODO: Perhaps, if you have a doc with <pre> tags that matches
6+
// this, it should become a flaw.
7+
const IGNORE = new Set(["none", "text", "plain", "unix"]);
8+
9+
/**
10+
* Mutate the `$` instance by adding headers to <pre> tags containing code blocks.
11+
*
12+
*/
13+
export function wrapCodeExamples($: cheerio.CheerioAPI) {
14+
// Our content will be like this: `<pre class="brush:js">` or
15+
// `<pre class="brush: js">` so we're technically not looking for an exact
16+
// match. The wildcard would technically match `<pre class="brushetta">`
17+
// too. But within the loop, we do a more careful regex on the class name
18+
// and only proceed if it's something sensible.
19+
$("pre[class*=brush]").each((_, element) => {
20+
// The language is whatever string comes after the `brush(:)`
21+
// portion of the class name.
22+
const $pre = $(element);
23+
24+
const className = $pre.attr("class").toLowerCase();
25+
const match = className.match(/brush:?\s*([\w_-]+)/);
26+
if (!match) {
27+
return;
28+
}
29+
const name = match[1].replace("-nolint", "");
30+
if (IGNORE.has(name)) {
31+
// Seems to exist a couple of these in our docs. Just bail.
32+
return;
33+
}
34+
const code = $pre.text();
35+
$pre.wrapAll(`<div class='code-example'></div>`);
36+
if (!$pre.hasClass("hidden")) {
37+
$(
38+
`<div class='example-header'><span class="language-name">${name}</span></div>`
39+
).insertBefore($pre);
40+
}
41+
const $code = $("<code>").text(code);
42+
43+
$pre.empty().append($code);
44+
});
45+
}

Diff for: build/curriculum.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { DocParent } from "../libs/types/document.js";
99
import { CURRICULUM_TITLE, DEFAULT_LOCALE } from "../libs/constants/index.js";
1010
import * as kumascript from "../kumascript/index.js";
1111
import LANGUAGES_RAW from "../libs/languages/index.js";
12-
import { syntaxHighlight } from "./syntax-highlight.js";
12+
import { wrapCodeExamples } from "./code-headers.js";
1313
import {
1414
escapeRegExp,
1515
injectLoadingLazyAttributes,
@@ -321,7 +321,7 @@ export async function buildCurriculumPage(
321321
doc.hasMathML = true;
322322
}
323323
$("div.hidden").remove();
324-
syntaxHighlight($, doc);
324+
wrapCodeExamples($);
325325
injectNoTranslate($);
326326
injectLoadingLazyAttributes($);
327327
postProcessCurriculumLinks($, (p: string | undefined) => {

Diff for: build/index.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
} from "./flaws/index.js";
2929
import { checkImageReferences, checkImageWidths } from "./check-images.js";
3030
import { getPageTitle } from "./page-title.js";
31-
import { syntaxHighlight } from "./syntax-highlight.js";
31+
import { wrapCodeExamples } from "./code-headers.js";
3232
import { formatNotecards } from "./format-notecards.js";
3333
import buildOptions from "./build-options.js";
3434
import LANGUAGES_RAW from "../libs/languages/index.js";
@@ -456,8 +456,8 @@ export async function buildDocument(
456456
plainHTML = $.html();
457457
}
458458

459-
// Apply syntax highlighting all <pre> tags.
460-
syntaxHighlight($, doc);
459+
// Add headers to all <pre> tags with code.
460+
wrapCodeExamples($);
461461

462462
// Post process HTML so that the right elements gets tagged so they
463463
// *don't* get translated by tools like Google Translate.

Diff for: build/syntax-highlight.ts

-139
This file was deleted.

Diff for: client/src/blog/post.tsx

+2-5
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ import {
1414
BlogPostLimitedMetadata,
1515
AuthorMetadata,
1616
} from "../../../libs/types/blog";
17-
import {
18-
useCopyExamplesToClipboardAndAIExplain,
19-
useRunSample,
20-
} from "../document/hooks";
17+
import { useDecorateCodeExamples, useRunSample } from "../document/hooks";
2118
import { DEFAULT_LOCALE } from "../../../libs/constants";
2219
import { SignUpSection as NewsletterSignUp } from "../newsletter";
2320
import { TOC } from "../document/organisms/toc";
@@ -190,7 +187,7 @@ export function BlogPost(props: HydrationData) {
190187
);
191188
const { doc, blogMeta } = data || props || {};
192189
useRunSample(doc);
193-
useCopyExamplesToClipboardAndAIExplain(doc);
190+
useDecorateCodeExamples(doc);
194191
return (
195192
<>
196193
{doc && blogMeta && (

0 commit comments

Comments
 (0)