more markdown

This commit is contained in:
Snorre 2025-02-05 14:46:34 +01:00
parent e3c8ab0abb
commit 02cacc9a82
6 changed files with 161 additions and 41 deletions

View file

@ -0,0 +1,40 @@
const highlight = (map, source) => {
let output = source;
output = output.replace(/("[^"]+")/g, `<span class="string">$1</span>`)
for (let keyword of map.keywords) {
output = output.replaceAll(keyword, `<span class="keyword">${keyword}</span>`)
}
for (let keyword of map.altkeywords) {
output = output.replaceAll(keyword, `<span class="keyword-alt">${keyword}</span>`)
}
// TODO: predicate for function calls to be replaced
// for (let func in map.functions) {
// output = output.replace(func, `<span class="function">${func}</span>`)
// }
output = output.replace(/(\d+)/g, `<span class="number">$1</span>`)
return output;
}
const maps = {
cpp: {
keywords: [
"auto",
"void",
"struct"
],
altkeywords: [
"const",
"static",
"int",
"std::string",
"std::unique_ptr",
"char",
],
}
};

43
public/colours.css Normal file
View file

@ -0,0 +1,43 @@
:root {
--background: #2e3440;
--background-text: #3b4252;
--border: #5e81ac;
--border2: #b48ead;
--text: #eceff4;
--link: #88c0d0;
--link-visited: #81a1c1;
--padding: 10px 20px;
--margin: 4px;
--gap: 10px;
--radius: 4px;
}
pre.codeblock {
--keyword: #ebcb8b;
--keyword-alt: #bf616a;
--string: #a3be8c;
--function: #b48ead;
--number: #81a1c1;
}
pre.codeblock span.keyword {
color: var(--keyword);
}
pre.codeblock span.keyword-alt {
color: var(--keyword-alt);
}
pre.codeblock span.string {
color: var(--string)
}
pre.codeblock span.function {
color: var(--function)
}
pre.codeblock span.number {
color: var(--number)
}

View file

@ -1,20 +1,5 @@
@import url(https://fonts.bunny.net/css?family=chivo-mono:500); @import url(https://fonts.bunny.net/css?family=chivo-mono:500);
@import url(/colours.css);
:root {
--background: #2e3440;
--background-text: #3b4252;
--border: #5e81ac;
--border2: #b48ead;
--text: #eceff4;
--link: #88c0d0;
--link-visited: #81a1c1;
--padding: 10px 20px;
--margin: 4px;
--gap: 10px;
--radius: 4px;
}
code { code {
background: var(--background-text); background: var(--background-text);
@ -23,6 +8,14 @@ code {
border-radius: var(--radius); border-radius: var(--radius);
} }
pre.codeblock {
background: var(--background-text);
color: var(--text);
padding: 2px 4px;
border-radius: var(--radius);
width: 100%;
}
html { html {
color: var(--text); color: var(--text);
background-color: var(--background); background-color: var(--background);
@ -31,6 +24,7 @@ html {
body { body {
background-color: initial !important; background-color: initial !important;
font-variant-ligatures: none;
} }
a { a {

View file

@ -16,6 +16,10 @@ const md2tokens = (markdown, newline) => {
return false; return false;
} }
let peek = (a) => {
return markdown[i + a];
}
let advance = () => { let advance = () => {
i++; i++;
if (i < markdown.length) if (i < markdown.length)
@ -25,8 +29,12 @@ const md2tokens = (markdown, newline) => {
} }
let capture_until = (c) => { let capture_until = (c) => {
return capture_until_predicate((i) => markdown[i] == c);
}
let capture_until_predicate = (f) => {
let capture = ""; let capture = "";
while (markdown[i] != c && markdown.length > i) { while (!f(i) && markdown.length > i) {
capture += markdown[i]; capture += markdown[i];
i++; i++;
} }
@ -95,7 +103,6 @@ const md2tokens = (markdown, newline) => {
let depth_he = 0; let depth_he = 0;
do { do {
depth_he++; depth_he++;
} while (match("#")); } while (match("#"));
while (markdown[i] != "\n" && markdown.length > i) { while (markdown[i] != "\n" && markdown.length > i) {
@ -124,17 +131,19 @@ const md2tokens = (markdown, newline) => {
break; break;
} }
let url = capture_until("\""); let url = capture_until_predicate((i) => markdown[i] == "\"" || markdown[i] == ")");
advance(); let title = "";
let title = capture_until("\""); if (match("\"")) { // has title
advance(); title = capture_until("\"");
advance();
}
if (!match(")")) { if (!match(")")) {
current_string = `![${alt_text}](${url} "${title}"`; current_string = `![${alt_text}](${url} "${title}"`;
def(); def();
break; break;
} }
tokens.push({type:"image", alt: alt_text, url: url, title: title}) tokens.push({ type: "image", alt: alt_text, url: url, title: title })
break; break;
case '-': case '-':
@ -153,25 +162,54 @@ const md2tokens = (markdown, newline) => {
items.push(md2tokens(text, false)); items.push(md2tokens(text, false));
} while (match("-")); } while (match("-"));
tokens.push({type:"ul", items: items}); tokens.push({ type: "ul", items: items });
break; break;
case '\n': case '\n':
if (newline_count > 2) if (newline_count > 2)
break; break;
newline = true; newline = true;
newline_count++; newline_count++;
finish(); finish();
tokens.push({ type: "newline" }) tokens.push({ type: "newline" })
break; break;
case '[':
finish();
advance();
let text = capture_until("]");
advance();
if (!match("(")) {
current_string = `[${text}]`;
def();
break;
}
let link = capture_until(")");
tokens.push({ type: "link", link: link, text: text });
break;
case '`': case '`':
finish(); finish();
advance(); advance();
current_string = capture_until("`"); let stop = (i) => markdown[i] == "`";
finish("inlinecode"); let type_c = "inlinecode";
let language = "";
if (peek(0) == "`" && peek(1) == "`") { // multiline code block
advance(); advance();
language = capture_until("\n");
let f = (i) => markdown[i] == "`";
stop = (i) => f(i) && f(i + 1) && f(i + 2);
type_c = "codeblock";
}
current_string = capture_until_predicate(stop);
tokens.push({ type: type_c, content: current_string, language: language });
current_string = "";
if (type_c == "codeblock") { advance(); advance(); } // remove trailing `
break; break;
default: default:
@ -187,6 +225,14 @@ const md2tokens = (markdown, newline) => {
return tokens; return tokens;
}; };
const highlight_code = (language, code) => {
let map = maps[language];
if (map == undefined)
return code;
return highlight(map, code);
}
const tokens2html = (tokens) => { const tokens2html = (tokens) => {
let output = ""; let output = "";
@ -208,7 +254,7 @@ const tokens2html = (tokens) => {
output += "<br>" output += "<br>"
break; break;
case "image": case "image":
output += `<p style="text-align:center"><img src="${token.url}" alt="${token.alt}"></p>`; output += `<p style="text-align:center"><img src="${token.url}" alt="${token.alt}"><br>${token.title}</p>`;
break break
case "ul": case "ul":
console.log(token); console.log(token);
@ -221,6 +267,12 @@ const tokens2html = (tokens) => {
case "inlinecode": case "inlinecode":
output += `<code>${token.content}</code>`; output += `<code>${token.content}</code>`;
break; break;
case "codeblock":
output += `<pre class="codeblock" data-language="${token.language}">${highlight_code(token.language, token.content)}</pre>`
break;
case "link":
output += `<a href="${token.link}">${token.text}</a>`;
break;
} }
} }

View file

@ -25,6 +25,7 @@
<a href="/" style="color: inherit; text-decoration: inherit"><h1>SpoodyThe<span style="color:var(--background-text)">.</span>One</h1></a> <a href="/" style="color: inherit; text-decoration: inherit"><h1>SpoodyThe<span style="color:var(--background-text)">.</span>One</h1></a>
</div> </div>
<div class="content" style="grid-area: content; text-align: left"> <div class="content" style="grid-area: content; text-align: left">
<h2>Loading...</h2>
</div> </div>
<div class="footer" style="grid-area: footer; text-align: center"> <div class="footer" style="grid-area: footer; text-align: center">
<a href="#">Back to the top</a> <a href="#">Back to the top</a>
@ -33,12 +34,10 @@
<div id="background"></div> <div id="background"></div>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/code_highlighter.js"></script>
<script src="/md2html.js"></script> <script src="/md2html.js"></script>
<script> <script>
(async () => { (async () => {
// let terms = "Functions Vectors Evaluate Isolate Solve Matrix Tensor Calculus Derivation Limit Procedures Scopes Statements Interpreter Parser Lexer".split(" ");
// generate_background(terms);
// document.querySelector(".header").innerHTML = md2html({{}});
try { try {
let post = new URLSearchParams(window.location.search).get("post"); let post = new URLSearchParams(window.location.search).get("post");
let response = await fetch(`/posts/${post}.md`); let response = await fetch(`/posts/${post}.md`);

View file

@ -1,13 +1,5 @@
Functions Vectors Evaluate Isolate Solve Matrix Tensor Calculus Derivation Limit Procedures Scopes Statements Interpreter Parser Lexer Functions Vectors Evaluate Isolate Solve Matrix Tensor Calculus Derivation Limit Procedures Scopes Statements Interpreter Parser Lexer
# Openbirch # Openbirch
Openbirch is a programming language that I made together with my friend from school. Cool fucking cas tool.
It was an attempt at making a CAS tool to use instead of Maple (the UX is terrible).
The biggest challenge besides creating a programming language was creating a programming language ![image of openbirch](/openbirch/openbirch.png "Cool image of the cool fucking cas tool")
where any variable could be undefined at runtime, but still used to define other variables.
An example of this would be `x := 2*y`. Here `y` is not defined, but it is still used to define `x`.
This was a unique challenge that was solved by representing everything as a *tree*
![tree representation](/openbirch/tree.png "Tree Representation")