diff --git a/public/css.css b/public/css.css new file mode 100644 index 0000000..bb9fba4 --- /dev/null +++ b/public/css.css @@ -0,0 +1,100 @@ +@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; +} + +code { + background: var(--background-text); + color: var(--text); + padding: 2px 4px; + border-radius: var(--radius); +} + +html { + color: var(--text); + background-color: var(--background); + font-family: 'Chivo Mono', monospace; +} + +body { + background-color: initial !important; +} + +a { + color: var(--link); +} + +a:visited { + color: var(--link-visited); +} + +body { + min-height: 100vh; + min-width: 100vw; + margin: 0px; + padding: 0px; + + display: flex; + align-items: center; + justify-content: center; + + line-height: 1.5; +} + +#content { + display: grid; + grid-template-areas: + "header1 header1 header1" + "content1 content2 content2" + "footer1 footer2 footer3" + ; + grid-template-columns: 1fr 1fr 1fr; + grid-gap: var(--gap); + padding: var(--padding); +} + +#content>div { + background: var(--background); + border: 4px solid var(--border); + border-radius: var(--radius); + padding: var(--padding); + align-content: center; +} + +#content>div:nth-child(3n+1) { + border: 4px solid var(--border2); +} + +#background { + position: fixed; + z-index: -3; + + left: 0; + right: 0; + top: 0; + bottom: 0; + + color: var(--background-text); + opacity: 0.3; + + aspect-ratio: 1/1; + + transform-origin: top; + transform: scale(150%) rotate(-20deg) translateY(-25%); + + align-content: center; + text-align: center; +} diff --git a/public/index.html b/public/index.html index 6d85d95..5189848 100644 --- a/public/index.html +++ b/public/index.html @@ -2,131 +2,53 @@ - +
-
something something snorre.net
+
+

SpoodyThe.One

+
-
content
-
content
-
content
+
+

Things I like

+ +
+
+

Projects I've finished

+ +
+ - -
+ diff --git a/public/main.js b/public/main.js new file mode 100644 index 0000000..c6e759a --- /dev/null +++ b/public/main.js @@ -0,0 +1,15 @@ +const generate_background = ((terms) => { + let str = ""; + terms = terms == null ? "${i} :3 Nix Linux Test Portchain Programming Rust C++ Openbirch Godot".split(" ") : terms; + for (let i = 0; i < 5000; i++) { + let idx = Math.floor(Math.random() * terms.length); + str += terms[idx] + " "; + } + + + let idx = Math.floor(Math.random() * terms.length); + document.getElementById("background").innerText = str; + try { + document.querySelector(".footer>marquee").innerText = terms[idx] + " Footer"; + } catch (e) {} +}) diff --git a/public/md2html.js b/public/md2html.js new file mode 100644 index 0000000..5d3e2a2 --- /dev/null +++ b/public/md2html.js @@ -0,0 +1,228 @@ +const md2tokens = (markdown, newline) => { + // Simple lexer and parser + let i = 0; + let current_string = ""; + newline = newline == null ? true : newline; + let newline_count = newline ? 1 : 0; + + let tokens = []; + + let match = (c) => { + if (c == markdown[i]) { + i++; + return true; + } + + return false; + } + + let advance = () => { + i++; + if (i < markdown.length) + return true + + return false + } + + let capture_until = (c) => { + let capture = ""; + while (markdown[i] != c && markdown.length > i) { + capture += markdown[i]; + i++; + } + return capture; + } + + let finish = (type) => { + if (current_string.trim().length == 0) { + current_string = ""; + return; + } + + tokens.push({ type: type == null ? "span" : type, content: current_string }) + current_string = ""; + } + + let def = () => { + current_string += markdown[i]; + newline = false; + newline_count = 0; + } + + while (i < markdown.length) { + switch (markdown[i]) { + case '\\': + i++; + current_string += markdown[i]; + break; + + case '*': + finish(); + advance(); + let depth_em = 1; + let type = "em"; + if (match("*")) { + type = "bold"; + depth_em = 2; + } + + let found_match = () => { + for (let j = 0; j < depth_em; j++) { + if (markdown[i + j] != "*") + return false + } + return true + } + + while (!found_match()) { + current_string += markdown[i]; + if (!advance()) + break; + } + + advance(); + + finish(type); + break; + + case "#": + if (!newline) { + def(); + break; + } + + finish(); + let depth_he = 0; + do { + depth_he++; + + } while (match("#")); + + while (markdown[i] != "\n" && markdown.length > i) { + current_string += markdown[i]; + i++ + } + + tokens.push({ type: "header", level: depth_he, content: current_string }); + current_string = ""; + break; + + case '!': + if (markdown[i + 1] != "[") { + def(); + break; + } + + finish(); + advance(); + advance(); + let alt_text = capture_until("]"); + advance(); + if (!match("(")) { + current_string = `![${alt_text}]`; + def(); + break; + } + + let url = capture_until("\""); + advance(); + let title = capture_until("\""); + advance(); + if (!match(")")) { + current_string = `![${alt_text}](${url} "${title}"`; + def(); + break; + } + + tokens.push({type:"image", alt: alt_text, url: url, title: title}) + break; + + case '-': + if (!newline) { + def(); + break; + } + + let items = []; + + advance(); + + do { + let text = capture_until("\n"); + advance(); + items.push(md2tokens(text, false)); + } while (match("-")); + + 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(); + current_string = capture_until("`"); + finish("inlinecode"); + break; + + default: + def() + } + i++; + } + + finish(); + + console.log(tokens); + + return tokens; +}; + +const tokens2html = (tokens) => { + let output = ""; + + for (let token of tokens) { + switch (token.type) { + case "span": + output += `${token.content}`; + break + case "bold": + output += `${token.content}` + break; + case "em": + output += `${token.content}` + break; + case "header": + output += `${token.content}` + break; + case "newline": + output += "
" + break; + case "image": + output += `

${token.alt}

`; + break + case "ul": + console.log(token); + output += ""; + break; + case "inlinecode": + output += `${token.content}`; + break; + } + } + + return output; +} diff --git a/public/posts/index.html b/public/posts/index.html new file mode 100644 index 0000000..a39f45e --- /dev/null +++ b/public/posts/index.html @@ -0,0 +1,66 @@ + + + + + + + + + +
+ +
+
+ +
+ +
+ + + + + + diff --git a/public/posts/openbirch.md b/public/posts/openbirch.md new file mode 100644 index 0000000..d8a898b --- /dev/null +++ b/public/posts/openbirch.md @@ -0,0 +1,13 @@ +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). + +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* + +![tree representation](/openbirch/tree.png "Tree Representation") diff --git a/public/test.png b/public/test.png new file mode 100644 index 0000000..d23ef05 Binary files /dev/null and b/public/test.png differ diff --git a/src/main.rs b/src/main.rs index c05caf5..7b02a35 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use std::{ env::current_dir, + ffi::OsStr, io::{BufRead, BufReader, Write}, net::{TcpListener, TcpStream}, path::PathBuf, @@ -38,7 +39,16 @@ impl Request { "POST" => RequestMethod::POST, _ => panic!("Unknown method"), }, - path: Some(parts.next().expect("Invalid request").to_string()), + path: Some( + parts + .next() + .expect("Invalid request") + .to_string() + .split("?") + .next() + .unwrap() + .to_string(), + ), } } pub fn file(&self) -> Option { @@ -65,6 +75,22 @@ impl Request { } } +fn get_mime_type<'a>(extension: Option<&'a OsStr>) -> String { + if extension.is_none() { + return "text/text".to_string(); + } + + let s = extension.unwrap().to_str(); + match s { + Some("js") => "text/javascript".to_string(), + Some("md") => "text/markdown".to_string(), + Some("css") => "text/css".to_string(), + Some("html") => "text/html".to_string(), + Some("png") => "image/png".to_string(), + _ => "text/text".to_string(), + } +} + fn handle_connection(mut stream: TcpStream) { let buf_reader = BufReader::new(&stream); let http_request: Vec<_> = buf_reader @@ -83,13 +109,24 @@ fn handle_connection(mut stream: TcpStream) { println!("Requested file: {:#?}", req.file()); + let mut response_content = vec![]; + let response = match req.file() { - Some(path) => match std::fs::read_to_string(path) { - Ok(content) => format!("HTTP/1.1 200 OK{0}Content-Length: {1}{0}{0}{content}", CLRF, content.len()), - Err(e) => format!("HTTP/1.1 500{0}{0}{e}", CLRF), - } - None => format!("HTTP/1.1 500{0}{0}", CLRF), + Some(path) => match std::fs::read(&path) { + Ok(content) => { + let len = &content.len(); + response_content = content; + format!( + "HTTP/1.1 200 OK{0}Content-Type: {2}{0}Content-Length: {1}{0}{0}", + CLRF, + len, + get_mime_type(path.extension()) + )}, + Err(e) => format!("HTTP/1.1 404{0}{0}{e}", CLRF), + }, + None => format!("HTTP/1.1 404{0}{0}", CLRF), }; stream.write_all(response.as_bytes()).unwrap(); + stream.write_all(&response_content).unwrap(); }