diff --git a/Cargo.lock b/Cargo.lock index 95a47c5..1fba3dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.20" @@ -35,6 +41,55 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -107,12 +162,42 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + [[package]] name = "binascii" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -188,7 +273,11 @@ checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", + "serde", + "time 0.1.45", + "wasm-bindgen", "winapi 0.3.9", ] @@ -214,6 +303,74 @@ dependencies = [ "phf_codegen", ] +[[package]] +name = "clap" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +dependencies = [ + "anstream", + "anstyle", + "bitflags 1.3.2", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +dependencies = [ + "heck", + "proc-macro2 1.0.59", + "quote 1.0.28", + "syn 2.0.18", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "comrak" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482aa5695bca086022be453c700a40c02893f1ba7098a2c88351de55341ae894" +dependencies = [ + "clap", + "entities", + "memchr", + "once_cell", + "regex", + "shell-words", + "slug", + "syntect", + "typed-arena", + "unicode_categories", + "xdg", +] + [[package]] name = "cookie" version = "0.11.5" @@ -250,6 +407,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -375,6 +541,12 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + [[package]] name = "errno" version = "0.3.1" @@ -396,6 +568,16 @@ dependencies = [ "libc", ] +[[package]] +name = "fancy-regex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" +dependencies = [ + "bit-set", + "regex", +] + [[package]] name = "fastrand" version = "1.9.0" @@ -431,6 +613,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -635,6 +827,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -659,6 +857,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "http" version = "0.2.9" @@ -951,6 +1158,21 @@ version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +[[package]] +name = "line-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +dependencies = [ + "safemem", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -1033,6 +1255,15 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.6.23" @@ -1199,6 +1430,28 @@ version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +[[package]] +name = "onig" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +dependencies = [ + "bitflags 1.3.2", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "overload" version = "0.1.1" @@ -1389,6 +1642,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "plist" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590" +dependencies = [ + "base64 0.21.2", + "indexmap", + "line-wrap", + "quick-xml", + "serde", + "time 0.3.21", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1426,6 +1699,15 @@ dependencies = [ "yansi", ] +[[package]] +name = "quick-xml" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "0.6.13" @@ -1798,6 +2080,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha2" version = "0.10.6" @@ -1818,6 +2113,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1897,6 +2198,12 @@ dependencies = [ "loom", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "0.15.44" @@ -1919,13 +2226,41 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syntect" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c454c27d9d7d9a84c7803aaa3c50cd088d2906fe3c6e42da3209aa623576a8" +dependencies = [ + "bincode", + "bitflags 1.3.2", + "fancy-regex", + "flate2", + "fnv", + "lazy_static", + "once_cell", + "onig", + "plist", + "regex-syntax 0.6.29", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + [[package]] name = "tegakituesday" version = "0.1.0" dependencies = [ + "chrono", + "comrak", "rocket 0.5.0-rc.3", "rocket_contrib", "rocket_dyn_templates", + "serde", + "serde_yaml", ] [[package]] @@ -1963,6 +2298,16 @@ dependencies = [ "unic-segment", ] +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.40" @@ -2229,6 +2574,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.16.0" @@ -2352,6 +2703,18 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" + [[package]] name = "url" version = "1.7.2" @@ -2363,6 +2726,12 @@ dependencies = [ "percent-encoding 1.0.1", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" @@ -2670,6 +3039,24 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "xdg" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688597db5a750e9cad4511cb94729a078e274308099a0382b5b8203bbc767fee" +dependencies = [ + "home", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index e2b08c4..2304143 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +chrono = { version = "0.4.26", features = ["serde"] } +comrak = "0.18.0" rocket = "=0.5.0-rc.3" rocket_contrib = { version = "0.4.11", features = ["templates"] } rocket_dyn_templates = { version = "0.1.0-rc.3", features = ["tera"] } +serde = "1.0.163" +serde_yaml = "0.9.21" diff --git a/src/challenge.rs b/src/challenge.rs new file mode 100644 index 0000000..b98c865 --- /dev/null +++ b/src/challenge.rs @@ -0,0 +1,128 @@ +use std::str::FromStr; + +use serde::{Deserialize, Deserializer, Serialize}; +use serde_yaml::Value; + +#[derive(Serialize, Deserialize)] +pub struct Challenge { + pub japanese: Vec>>, + pub english: Option>, + pub song: Option, + pub youtube: Option, + pub spotify: Option, + pub translation: Option, + pub suggester: Option, + pub date: chrono::NaiveDate, +} + +#[derive(Serialize, Deserialize)] +pub struct Song { + pub japanese: Option, + pub english: Option, +} + +#[derive(Serialize)] +pub struct ChallengeWord { + pub dictionary: Option, + pub pos: Option, + pub text: Option>, +} + +impl<'de> Deserialize<'de> for ChallengeWord { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value = Deserialize::deserialize(deserializer)?; + let map = if let Value::Mapping(map) = value { + map + } else { + return Err(serde::de::Error::invalid_type( + serde::de::Unexpected::Other("not a string or map"), + &"a string or map", + )); + }; + let dictionary = map.get("dictionary").and_then(|value| match value { + Value::Null => None, + _ => Some(value.as_str().unwrap().to_owned()), + }); + let pos: Option = map + .get("pos") + .map(|value| value.as_str().unwrap().parse().unwrap()); + Ok(ChallengeWord { + dictionary, + pos, + text: map.get("text").map(|value| match value { + Value::String(string) => vec![Furigana { + kanji: string.clone(), + furigana: None, + }], + Value::Sequence(sequence) => sequence + .iter() + .map(|value| match value { + Value::String(kanji) => Furigana { + kanji: kanji.to_owned(), + furigana: None, + }, + Value::Mapping(mapping) => { + let (kanji, furigana) = mapping.iter().next().unwrap(); + Furigana { + kanji: kanji.as_str().unwrap().to_owned(), + furigana: Some(furigana.as_str().unwrap().to_owned()), + } + } + _ => panic!(), + }) + .collect(), + _ => panic!(), + }), + }) + } +} +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum PartOfSpeech { + Noun, + Adjective, + Verb, + Adverb, + Particle, + Phrase, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct ParsePartOfSpeechError; + +impl FromStr for PartOfSpeech { + type Err = ParsePartOfSpeechError; + fn from_str(s: &str) -> Result { + use PartOfSpeech::*; + Ok(match s { + "noun" => Noun, + "adjective" => Adjective, + "verb" => Verb, + "adverb" => Adverb, + "particle" => Particle, + "phrase" => Phrase, + _ => return Err(ParsePartOfSpeechError), + }) + } +} + +#[derive(Serialize, Deserialize)] +pub struct Furigana { + pub kanji: String, + pub furigana: Option, +} + +#[derive(Serialize, Deserialize)] +pub struct Translation { + pub author: Option, + pub site: TranslationSite, +} + +#[derive(Serialize, Deserialize)] +pub struct TranslationSite { + pub name: String, + pub link: String, +} diff --git a/src/main.rs b/src/main.rs index dc89838..b59d1fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,56 @@ -#[macro_use] extern crate rocket; +#[macro_use] +extern crate rocket; -use rocket_dyn_templates::{Template, context}; +use core::panic; +use rocket_dyn_templates::{context, Template}; +use std::fs; -#[get("/")] -fn index() -> Template { - Template::render("index", context! { - challenge: 114, - }) +mod challenge; +use challenge::Challenge; + +#[get("/")] +fn get_challenge(challenge: u32) -> Template { + Template::render( + "index", + context! { + challenge, + content: { + use comrak::{parse_document, Arena, ComrakOptions}; + let options = { + let mut options = ComrakOptions::default(); + options.extension.front_matter_delimiter = Some("---".to_owned()); + options + }; + let arena = Arena::new(); + let root = parse_document( + &arena, + &fs::read_to_string(format!("content/challenges/{challenge}.md")).expect("Couldn't find challenge file"), + &options, + ); + if let Some(node) = root.children().next() { + if let comrak::nodes::NodeValue::FrontMatter(frontmatter) = &node.data.borrow().value { + let frontmatter = { + // Trim starting and ending fences + let lines: Vec<&str> = frontmatter.trim().lines().collect(); + lines[1..lines.len() - 1].join("\n") + }; + let challenge: Challenge = serde_yaml::from_str(&frontmatter).unwrap(); + challenge + } else { + panic!("No frontmatter!") + } + } else { + panic!("Empty document!") + } + } + }, + ) } #[launch] fn rocket() -> _ { - let config = rocket::Config::figment() - .merge(("port", 1313)); + let config = rocket::Config::figment().merge(("port", 1313)); rocket::custom(config) - .mount("/", routes![index]) + .mount("/", routes![get_challenge]) .attach(Template::fairing()) -} \ No newline at end of file +} diff --git a/templates/index.html.tera b/templates/index.html.tera index ec0ea07..21b46d5 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -5,5 +5,36 @@

Welcome to Tegaki Tuesday #{{ challenge }}!

+ Previous + Next +
+ {% for line in content.japanese %} + {% for subline in line %} +

+ {% for word in subline %} + {% for segment in word.text %} + {{ segment.kanji }}({{ segment.furigana | safe }}) + {% endfor %} + {% endfor %} +

+ {% endfor %} + {% endfor %} +
+ {% if content.translation %} +

+ Translation + {% if content.translation.author %}by {{ content.translation.author }}{% endif %} + {% if content.translation.site %} via + {% if content.translation.site.link %} + {{ content.translation.site.name }} + {% else %} + {{ content.translation.site.name }} + {% endif %} + {% endif %} +

+ {% endif %} + {% if content.suggester %} +

This challenge was suggested by {{ content.suggester }} using the -h suggest command.

+ {% endif %} \ No newline at end of file