diff --git a/public/code_highlighter.js b/public/code_highlighter.js new file mode 100644 index 0000000..c8ee430 --- /dev/null +++ b/public/code_highlighter.js @@ -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", + ], + } +}; diff --git a/public/colours.css b/public/colours.css new file mode 100644 index 0000000..e43956c --- /dev/null +++ b/public/colours.css @@ -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) +} diff --git a/public/css.css b/public/css.css index bb9fba4..c256e10 100644 --- a/public/css.css +++ b/public/css.css @@ -1,20 +1,5 @@ @import url(https://fonts.bunny.net/css?family=chivo-mono:500); - -: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; -} +@import url(/colours.css); code { background: var(--background-text); @@ -23,6 +8,14 @@ code { border-radius: var(--radius); } +pre.codeblock { + background: var(--background-text); + color: var(--text); + padding: 2px 4px; + border-radius: var(--radius); + width: 100%; +} + html { color: var(--text); background-color: var(--background); @@ -31,6 +24,7 @@ html { body { background-color: initial !important; + font-variant-ligatures: none; } a { diff --git a/public/md2html.js b/public/md2html.js index 5d3e2a2..df197c6 100644 --- a/public/md2html.js +++ b/public/md2html.js @@ -16,6 +16,10 @@ const md2tokens = (markdown, newline) => { return false; } + let peek = (a) => { + return markdown[i + a]; + } + let advance = () => { i++; if (i < markdown.length) @@ -25,8 +29,12 @@ const md2tokens = (markdown, newline) => { } let capture_until = (c) => { + return capture_until_predicate((i) => markdown[i] == c); + } + + let capture_until_predicate = (f) => { let capture = ""; - while (markdown[i] != c && markdown.length > i) { + while (!f(i) && markdown.length > i) { capture += markdown[i]; i++; } @@ -95,7 +103,6 @@ const md2tokens = (markdown, newline) => { let depth_he = 0; do { depth_he++; - } while (match("#")); while (markdown[i] != "\n" && markdown.length > i) { @@ -124,17 +131,19 @@ const md2tokens = (markdown, newline) => { break; } - let url = capture_until("\""); - advance(); - let title = capture_until("\""); - advance(); + let url = capture_until_predicate((i) => markdown[i] == "\"" || markdown[i] == ")"); + let title = ""; + if (match("\"")) { // has title + title = capture_until("\""); + advance(); + } if (!match(")")) { current_string = `; break; } - tokens.push({type:"image", alt: alt_text, url: url, title: title}) + tokens.push({ type: "image", alt: alt_text, url: url, title: title }) break; case '-': @@ -153,25 +162,54 @@ const md2tokens = (markdown, newline) => { items.push(md2tokens(text, false)); } while (match("-")); - tokens.push({type:"ul", items: items}); + tokens.push({ type: "ul", items: items }); break; case '\n': if (newline_count > 2) break; - + newline = true; newline_count++; finish(); tokens.push({ type: "newline" }) 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 '`': finish(); advance(); - current_string = capture_until("`"); - finish("inlinecode"); + let stop = (i) => markdown[i] == "`"; + 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; default: @@ -187,6 +225,14 @@ const md2tokens = (markdown, newline) => { return tokens; }; +const highlight_code = (language, code) => { + let map = maps[language]; + if (map == undefined) + return code; + + return highlight(map, code); +} + const tokens2html = (tokens) => { let output = ""; @@ -208,7 +254,7 @@ const tokens2html = (tokens) => { output += "<br>" break; 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 case "ul": console.log(token); @@ -221,6 +267,12 @@ const tokens2html = (tokens) => { case "inlinecode": output += `<code>${token.content}</code>`; 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; } } diff --git a/public/posts/index.html b/public/posts/index.html index 5168d8f..1323957 100644 --- a/public/posts/index.html +++ b/public/posts/index.html @@ -25,6 +25,7 @@ <a href="/" style="color: inherit; text-decoration: inherit"><h1>SpoodyThe<span style="color:var(--background-text)">.</span>One</h1></a> </div> <div class="content" style="grid-area: content; text-align: left"> + <h2>Loading...</h2> </div> <div class="footer" style="grid-area: footer; text-align: center"> <a href="#">Back to the top</a> @@ -33,12 +34,10 @@ <div id="background"></div> <script src="/main.js"></script> + <script src="/code_highlighter.js"></script> <script src="/md2html.js"></script> <script> (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 { let post = new URLSearchParams(window.location.search).get("post"); let response = await fetch(`/posts/${post}.md`); diff --git a/public/posts/openbirch.md b/public/posts/openbirch.md index d8a898b..d9d0264 100644 --- a/public/posts/openbirch.md +++ b/public/posts/openbirch.md @@ -1,13 +1,5 @@ Functions Vectors Evaluate Isolate Solve Matrix Tensor Calculus Derivation Limit Procedures Scopes Statements Interpreter Parser Lexer # Openbirch -Openbirch is a programming language that I made together with my friend from school. -It was an attempt at making a CAS tool to use instead of Maple (the UX is terrible). +Cool fucking cas tool. -The biggest challenge besides creating a programming language was creating a programming language -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* - - +