Skip to content

Commit

Permalink
Allow titles for code blocks (#127)
Browse files Browse the repository at this point in the history
* Allow titles for code blocks

* Add tests and CSS; fmt

* fix

---------

Co-authored-by: crowlkats <crowlkats@toaxl.com>
  • Loading branch information
josh-collinsworth and crowlKats authored Aug 28, 2024
1 parent f4ae669 commit 46fa230
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 130 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
cov_profile
deno.lock
deno.lock
.DS_Store
8 changes: 7 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"marked-footnote": "npm:marked-footnote@^1.2",
"marked-gfm-heading-id": "npm:marked-gfm-heading-id@^3.1",
"prismjs": "npm:prismjs@^1.29",
"prismjs-yaml": "npm:prismjs@^1.29/components/prism-yaml.js",
"sanitize-html": "npm:sanitize-html@^2.11",
"he": "npm:he@^1.2",
"katex": "npm:katex@^0.16",
Expand All @@ -29,6 +30,11 @@
"test": "deno test --allow-read --allow-env --allow-write --allow-run --allow-net"
},
"fmt": {
"exclude": ["./test/fixtures/alerts.md", "./test/fixtures/lineBreaks.md"]
"exclude": [
"./test/fixtures/alerts.md",
"./test/fixtures/lineBreaks.md",
"./test/fixtures/footnote.md",
"./example/content.md"
]
}
}
91 changes: 53 additions & 38 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { emojify } from "emoji";
import * as Marked from "marked";
import GitHubSlugger from "github-slugger";
import he from "he";
import katex from "katex";
import * as Marked from "marked";
import markedAlert from "marked-alert";
import markedFootnote from "marked-footnote";
import { gfmHeadingId } from "marked-gfm-heading-id";
import Prism from "prismjs";
import sanitizeHtml from "sanitize-html";
import he from "he";
import katex from "katex";
import "prismjs-yaml";

import { CSS, KATEX_CLASSES, KATEX_CSS } from "./style.ts";
export { CSS, KATEX_CSS, Marked };
import "https://esm.sh/prismjs@1.29.0/components/prism-yaml";

Marked.marked.use(markedAlert());
Marked.marked.use(gfmHeadingId());
Expand Down Expand Up @@ -39,11 +39,7 @@ export class Renderer extends Marked.Renderer {
this.#slugger = new GitHubSlugger();
}

heading(
text: string,
level: 1 | 2 | 3 | 4 | 5 | 6,
raw: string,
): string {
heading(text: string, level: 1 | 2 | 3 | 4 | 5 | 6, raw: string): string {
const slug = this.#slugger.slug(raw);
return `<h${level} id="${slug}"><a class="anchor" aria-hidden="true" tabindex="-1" href="#${slug}"><svg class="octicon octicon-link" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a>${text}</h${level}>\n`;
}
Expand All @@ -53,6 +49,13 @@ export class Renderer extends Marked.Renderer {
}

code(code: string, language?: string): string {
const isTitleIncluded = language?.match(/\stitle="(.+)"/);
let title = null;
if (isTitleIncluded) {
language = language!.split(" ")[0];
title = isTitleIncluded[1];
}

// a language of `ts, ignore` should really be `ts`
// and it should be lowercase to ensure it has parity with regular github markdown
language = language?.split(",")?.[0].toLocaleLowerCase();
Expand All @@ -70,7 +73,10 @@ export class Renderer extends Marked.Renderer {
return `<pre><code class="notranslate">${he.encode(code)}</code></pre>`;
}
const html = Prism.highlight(code, grammar, language!);
return `<div class="highlight highlight-source-${language} notranslate"><pre>${html}</pre></div>`;
const titleHtml = title
? `<div class="markdown-code-title">${title}</div>`
: ``;
return `<div class="highlight highlight-source-${language} notranslate">${titleHtml}<pre>${html}</pre></div>`;
}

link(href: string, title: string | null, text: string): string {
Expand Down Expand Up @@ -153,10 +159,11 @@ export function render(markdown: string, opts: RenderOptions = {}): string {

const marked_opts = getOpts(opts);

const html =
(opts.inline
const html = (
opts.inline
? Marked.marked.parseInline(markdown, marked_opts)
: Marked.marked.parse(markdown, marked_opts)) as string;
: Marked.marked.parse(markdown, marked_opts)
) as string;

if (opts.disableHtmlSanitization) {
return html;
Expand Down Expand Up @@ -231,6 +238,7 @@ export function render(markdown: string, opts: RenderOptions = {}): string {
"notranslate",
"markdown-alert",
"markdown-alert-*",
"markdown-code-title",
],
span: [
"token",
Expand Down Expand Up @@ -312,18 +320,22 @@ export function render(markdown: string, opts: RenderOptions = {}): string {
annotation: ["encoding"], // Only enabled when math is enabled
details: ["open"],
section: ["data-footnotes"],
input: ["checked", "disabled", {
name: "type",
values: ["checkbox"],
}],
input: [
"checked",
"disabled",
{
name: "type",
values: ["checkbox"],
},
],
};

return sanitizeHtml(html, {
transformTags: {
img: transformMedia,
video: transformMedia,
},
allowedTags: [...defaultAllowedTags, ...opts.allowedTags ?? []],
allowedTags: [...defaultAllowedTags, ...(opts.allowedTags ?? [])],
allowedAttributes: mergeAttributes(
defaultAllowedAttributes,
opts.allowedAttributes ?? {},
Expand Down Expand Up @@ -356,14 +368,12 @@ function stripTokens(

for (const token of tokens) {
if (token.type === "heading") {
sections[index].header = sections[index].header.trim().replace(
/\n{3,}/g,
"\n",
);
sections[index].content = sections[index].content.trim().replace(
/\n{3,}/g,
"\n",
);
sections[index].header = sections[index].header
.trim()
.replace(/\n{3,}/g, "\n");
sections[index].content = sections[index].content
.trim()
.replace(/\n{3,}/g, "\n");

sections.push({ header: "", depth: token.depth, content: "" });
index += 1;
Expand Down Expand Up @@ -488,20 +498,21 @@ export function stripSplitBySections(
markdown: string,
opts: RenderOptions = {},
): MarkdownSections[] {
markdown = emojify(markdown).replace(BLOCK_MATH_REGEXP, "").replace(
INLINE_MATH_REGEXP,
"",
);
markdown = emojify(markdown)
.replace(BLOCK_MATH_REGEXP, "")
.replace(INLINE_MATH_REGEXP, "");
const tokens = Marked.marked.lexer(markdown, {
...getOpts(opts),
tokenizer: new StripTokenizer(),
});

const sections: MarkdownSections[] = [{
header: "",
depth: 0,
content: "",
}];
const sections: MarkdownSections[] = [
{
header: "",
depth: 0,
content: "",
},
];
stripTokens(tokens, sections, false);

return sections;
Expand All @@ -511,7 +522,11 @@ export function stripSplitBySections(
* Strip all markdown syntax to get a plaintext output
*/
export function strip(markdown: string, opts: RenderOptions = {}): string {
return stripSplitBySections(markdown, opts).map((section) =>
section.header + "\n\n" + section.content
).join("\n\n").trim().replace(/\n{3,}/g, "\n") + "\n";
return (
stripSplitBySections(markdown, opts)
.map((section) => section.header + "\n\n" + section.content)
.join("\n\n")
.trim()
.replace(/\n{3,}/g, "\n") + "\n"
);
}
18 changes: 14 additions & 4 deletions style/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
&[align="center"] {
margin: 0 auto;
}

display: inline;
}

Expand All @@ -41,15 +41,15 @@
padding-top: 2px;
text-align: center;
}

ol {
list-style: decimal;
}

ul {
list-style: disc;
}

table {
width: fit-content;
}
Expand Down Expand Up @@ -123,6 +123,16 @@
}
}

.markdown-body .markdown-code-title {
background-color: var(--bgColor-muted, var(--color-canvas-subtle));
padding: 8px 16px;
border-bottom: 1px solid var(--borderColor-muted,var(--color-border-muted));
margin: 0;
font-size: 85%;
font-weight: bold;
display: block;
}

.sr-only {
position: absolute;
width: 1px;
Expand Down
Loading

0 comments on commit 46fa230

Please sign in to comment.