Remove client side syntax highlighting

This commit is contained in:
Araozu 2024-07-05 09:40:10 -05:00
parent 631acc8122
commit ebf62bcd5c
8 changed files with 37 additions and 161 deletions

View File

@ -1,7 +1,11 @@
--- ---
import { leftTrimDedent } from "./utils"; import { leftTrimDedent } from "./utils";
import { thp_highlighter } from "../lexer/highlighter";
const { thpcode } = Astro.props; const { thpcode } = Astro.props;
const html_code = thp_highlighter(leftTrimDedent(thpcode).join("\n"));
--- ---
<pre class="language-thp" data-language="thp"><code class="language-thp">{leftTrimDedent(thpcode).join("\n")}</code></pre> <pre
class="language-thp"
data-language="thp"><code class="language-thp" set:html={html_code} /><span class="absolute top-2 right-2 inline-block text-sm select-none opacity-75">thp</span></pre>

View File

@ -1,13 +1,11 @@
--- ---
import { trimAndDedent } from "./utils"; import Code from "./Code.astro"
const { thpcode } = Astro.props; const { thpcode } = Astro.props;
--- ---
<div class="flex h-full py-8 items-center"> <div class="flex h-full py-8 items-center">
<div class="p-4 w-full"> <div class="p-4 w-full">
<pre <Code thpcode={thpcode} />
class="language-thp"
data-language="thp"><code class="language-thp">{trimAndDedent(thpcode).join("\n")}</code></pre>
</div> </div>
</div> </div>

View File

@ -2,7 +2,7 @@
import { lex } from "../lexer/lexer"; import { lex } from "../lexer/lexer";
import type { Instruction } from "../thp_machine/machine_parser"; import type { Instruction } from "../thp_machine/machine_parser";
import { parse_str } from "../thp_machine/machine_parser"; import { parse_str } from "../thp_machine/machine_parser";
import { trimAndDedent } from "./utils"; import { leftTrimDedent } from "./utils";
const { code, steps } = Astro.props; const { code, steps } = Astro.props;
function highlightCode(lines: Array<string>): string { function highlightCode(lines: Array<string>): string {
@ -31,7 +31,7 @@ function highlightCode(lines: Array<string>): string {
return outLines.join("\n"); return outLines.join("\n");
} }
const codeHtml = highlightCode(trimAndDedent(code)); const codeHtml = highlightCode(leftTrimDedent(code));
let instructionSet: Array<Array<Instruction>>; let instructionSet: Array<Array<Instruction>>;
try { try {
instructionSet = parse_str(steps); instructionSet = parse_str(steps);

View File

@ -5,70 +5,6 @@
* - Picks the indentation level from the first non-white line * - Picks the indentation level from the first non-white line
* - Dedents the following lines * - Dedents the following lines
*/ */
export function trimAndDedent(input: string): Array<string> {
let lines = input.split("\n");
// Remove empty lines at the start
while (lines[0] === "") {
lines = lines.slice(1);
}
// Get indentation level
let indentationLevel = 0;
for (const char of lines[0]!) {
if (char === " ") {
indentationLevel += 1;
} else {
break;
}
}
// Enforce indentation, or trim
for (let i = 0; i < lines.length; i += 1) {
// If the line is empty, continue
const characters = lines[i]!.split("");
if (characters.length === 0) {
continue;
}
// If all characters are whitespace, append just a newline
const nonWhitespace = characters.find((x) => x !== " ");
if (nonWhitespace === undefined) {
lines[i] = "";
continue;
}
// Enforce indentation
if (characters.length < indentationLevel) {
throw new Error("Invalid indentation while parsing THP code: " + lines[i]);
}
let currentIndentation = 0;
for (const c of characters) {
if (c === " ") { currentIndentation += 1 }
else { break; }
}
if (currentIndentation < indentationLevel) {
throw new Error("Invalid indentation while parsing THP code: " + lines[i]);
}
lines[i] = characters.slice(4).join("");
}
// Remove empty lines at the end
let endPosition = lines.length - 1;
while (true) {
if (lines[endPosition] === "") {
lines = lines.slice(0, -1);
endPosition -= 1;
} else {
break;
}
}
return lines;
}
export function leftTrimDedent(input: string): Array<string> { export function leftTrimDedent(input: string): Array<string> {
let lines = input.split("\n"); let lines = input.split("\n");
let output: Array<string> = []; let output: Array<string> = [];

View File

@ -1,48 +1,4 @@
import { thp_highlighter, CodeJar } from "../lexer/highlighter"; import { thp_highlighter, CodeJar } from "../lexer/highlighter";
/** export function highlightOnDom() {}
* Highlights all THP code snippets mounted in the DOM with class .language-thp
*
* It assumes that the code is inside: <pre class="language-thp"><code>...
*/
export function highlightOnDom() {
const code_elements = document.querySelectorAll("code.language-thp");
for (const e of [...code_elements]) {
const el = e as HTMLElement;
// Some elements with .language-thp don't want to be processed
if (e.getAttribute("data-disabled") !== null) {
continue;
}
const pre_parent = el.parentElement!;
const new_div = document.createElement("div");
let code = el.innerHTML;
// Replace all &lt; with < and all &gt; with >
code = code.replace(/&lt;/g, "<").replace(/&gt;/g, ">");
el.parentElement!.className = "language-thp";
pre_parent.removeChild(el);
pre_parent.appendChild(new_div);
// Create and append a language name indicator
CodeJar(new_div, thp_highlighter, {
tab: " ",
}).updateCode(code);
}
const pre_elements = document.querySelectorAll("pre");
for (const pre_el of pre_elements) {
const language = pre_el.getAttribute("data-language");
if (language === null) { continue; }
// Create a visual indicador
const indicator = document.createElement("span");
indicator.className = "absolute top-2 right-2 inline-block text-sm select-none opacity-75";
indicator.innerText = language;
pre_el.appendChild(indicator);
}
}

View File

@ -1,9 +1,6 @@
import { lex } from "./lexer"; import { lex } from "./lexer";
import {CodeJar as Codejar} from "codejar";
export function thp_highlighter(editor: any) {
let code: string = editor.textContent;
export function thp_highlighter(code: string) {
let tokens = lex(code); let tokens = lex(code);
let highlighted_code = ""; let highlighted_code = "";
@ -12,7 +9,5 @@ export function thp_highlighter(editor: any) {
highlighted_code += `<span class="token ${token.token_type}">${token.v}</span>`; highlighted_code += `<span class="token ${token.token_type}">${token.v}</span>`;
} }
editor.innerHTML = highlighted_code; return highlighted_code;
} }
export const CodeJar = Codejar;

View File

@ -2,6 +2,28 @@
import BaseLayout from "../layouts/BaseLayout.astro"; import BaseLayout from "../layouts/BaseLayout.astro";
import Navbar from "../components/Navbar.astro"; import Navbar from "../components/Navbar.astro";
import HeroSection from "../components/HeroSection.astro"; import HeroSection from "../components/HeroSection.astro";
import { thp_highlighter } from "../lexer/highlighter";
import { leftTrimDedent } from "../components/utils";
const thpcode = `union Animal {
Dog(String),
Cat(String, Int),
}
val cat_name = Post::get("cat_name") ?? "Michifu"
val my_cat = Animal::Cat(cat_name, 9)
try change_fur_color(cat) else die("Not a cat")
match random_animal()
case Dog(name)
{
print("{name} has 1 live ")
}
case Cat(name, lives)
{
print("{name} has {lives}")
}`;
--- ---
<BaseLayout> <BaseLayout>
@ -95,7 +117,9 @@ import HeroSection from "../components/HeroSection.astro";
</g> </g>
</svg> </svg>
<div class="h-1"></div> <div class="h-1"></div>
<div id="editor" class="font-mono language-thp"></div> <div id="editor" class="font-mono language-thp">
<pre set:html={thp_highlighter(leftTrimDedent(thpcode).join("\n"))}></pre>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -194,38 +218,4 @@ import HeroSection from "../components/HeroSection.astro";
<br> <br>
Nullable types must be explicitly checked before using them. Nullable types must be explicitly checked before using them.
</HeroSection> </HeroSection>
<script>
import { thp_highlighter, CodeJar } from "../lexer/highlighter";
let jar = CodeJar(document.getElementById("editor")!, thp_highlighter, {
tab: " ",
});
jar.updateCode(
`union Animal {
Dog(String),
Cat(String, Int),
}
val cat_name = Post::get("cat_name") ?? "Michifu"
val my_cat = Animal::Cat(cat_name, 9)
try change_fur_color(cat) else die("Not a cat")
match random_animal()
case Dog(name)
{
print("{name} has 1 live ")
}
case Cat(name, lives)
{
print("{name} has {lives}")
}`,
);
</script>
<script>
import { highlightOnDom } from "../layouts/thpHighlighter";
document.addEventListener("DOMContentLoaded", highlightOnDom);
</script>
</BaseLayout> </BaseLayout>

View File

@ -101,6 +101,3 @@ fun TransactionItem(Transaction t) {
`} /> `} />