diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a46116 --- /dev/null +++ b/.gitignore @@ -0,0 +1,318 @@ +latex/ +# Created by https://www.toptal.com/developers/gitignore/api/latex,dotenv +# Edit at https://www.toptal.com/developers/gitignore?templates=latex,dotenv + +### dotenv ### +.env + +### LaTeX ### +## Core latex/pdflatex auxiliary files: +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.fmt +*.fot +*.cb +*.cb2 +.*.lb + +## Intermediate documents: +*.dvi +*.xdv +*-converted-to.* +# these rules might exclude image files for figures etc. +# *.ps +# *.eps +# *.pdf + +## Generated if empty string is given at "Please type another file name for output:" +.pdf + +## Bibliography auxiliary files (bibtex/biblatex/biber): +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.run.xml + +## Build tool auxiliary files: +*.fdb_latexmk +*.synctex +*.synctex(busy) +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync + +## Build tool directories for auxiliary files +# latexrun +latex.out/ + +## Auxiliary and intermediate files from other packages: +# algorithms +*.alg +*.loa + +# achemso +acs-*.bib + +# amsthm +*.thm + +# beamer +*.nav +*.pre +*.snm +*.vrb + +# changes +*.soc + +# comment +*.cut + +# cprotect +*.cpt + +# elsarticle (documentclass of Elsevier journals) +*.spl + +# endnotes +*.ent + +# fixme +*.lox + +# feynmf/feynmp +*.mf +*.mp +*.t[1-9] +*.t[1-9][0-9] +*.tfm + +#(r)(e)ledmac/(r)(e)ledpar +*.end +*.?end +*.[1-9] +*.[1-9][0-9] +*.[1-9][0-9][0-9] +*.[1-9]R +*.[1-9][0-9]R +*.[1-9][0-9][0-9]R +*.eledsec[1-9] +*.eledsec[1-9]R +*.eledsec[1-9][0-9] +*.eledsec[1-9][0-9]R +*.eledsec[1-9][0-9][0-9] +*.eledsec[1-9][0-9][0-9]R + +# glossaries +*.acn +*.acr +*.glg +*.glo +*.gls +*.glsdefs +*.lzo +*.lzs +*.slg +*.slo +*.sls + +# uncomment this for glossaries-extra (will ignore makeindex's style files!) +# *.ist + +# gnuplot +*.gnuplot +*.table + +# gnuplottex +*-gnuplottex-* + +# gregoriotex +*.gaux +*.glog +*.gtex + +# htlatex +*.4ct +*.4tc +*.idv +*.lg +*.trc +*.xref + +# hyperref +*.brf + +# knitr +*-concordance.tex +# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files +# *.tikz +*-tikzDictionary + +# listings +*.lol + +# luatexja-ruby +*.ltjruby + +# makeidx +*.idx +*.ilg +*.ind + +# minitoc +*.maf +*.mlf +*.mlt +*.mtc[0-9]* +*.slf[0-9]* +*.slt[0-9]* +*.stc[0-9]* + +# minted +_minted* +*.pyg + +# morewrites +*.mw + +# newpax +*.newpax + +# nomencl +*.nlg +*.nlo +*.nls + +# pax +*.pax + +# pdfpcnotes +*.pdfpc + +# sagetex +*.sagetex.sage +*.sagetex.py +*.sagetex.scmd + +# scrwfile +*.wrt + +# svg +svg-inkscape/ + +# sympy +*.sout +*.sympy +sympy-plots-for-*.tex/ + +# pdfcomment +*.upa +*.upb + +# pythontex +*.pytxcode +pythontex-files-*/ + +# tcolorbox +*.listing + +# thmtools +*.loe + +# TikZ & PGF +*.dpth +*.md5 +*.auxlock + +# titletoc +*.ptc + +# todonotes +*.tdo + +# vhistory +*.hst +*.ver + +# easy-todo +*.lod + +# xcolor +*.xcp + +# xmpincl +*.xmpi + +# xindy +*.xdy + +# xypic precompiled matrices and outlines +*.xyc +*.xyd + +# endfloat +*.ttt +*.fff + +# Latexian +TSWLatexianTemp* + +## Editors: +# WinEdt +*.bak +*.sav + +# Texpad +.texpadtmp + +# LyX +*.lyx~ + +# Kile +*.backup + +# gummi +.*.swp + +# KBibTeX +*~[0-9]* + +# TeXnicCenter +*.tps + +# auto folder when using emacs and auctex +./auto/* +*.el + +# expex forward references with \gathertags +*-tags.tex + +# standalone packages +*.sta + +# Makeindex log files +*.lpz + +# xwatermark package +*.xwm + +# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib +# option is specified. Footnotes are the stored in a file with suffix Notes.bib. +# Uncomment the next line to have this generated file ignored. +#*Notes.bib + +### LaTeX Patch ### +# LIPIcs / OASIcs +*.vtc + +# glossaries +*.glstex + +# End of https://www.toptal.com/developers/gitignore/api/latex,dotenv diff --git a/README.md b/README.md index 514d7d7..c4d2ef1 100644 --- a/README.md +++ b/README.md @@ -3,32 +3,49 @@ An Applied Physics student with a passion for programming! I have always enjoyed programming as a hobby, and would love to make it my carreer. Since then I have also combining this hobby with the hardware side of things. -Most recently I have picked up [Rust](https://rust-lang.org), and have fallen in love with this programming language. +Most recently I have picked up [Rust], and have fallen in love with this programming language. I'm also quite experienced with Linux as I have been daily driving it for the past decade at this point. Making me very familiar with the terminal and the different command line tools available. And have even been running my own Linux server for quite some time now! +[Rust]: https://rust-lang.org + + ## Projects ### [Z80 Computer](https://git.huizinga.dev/Z80/Z80) -The first big hardware project that I work on was building a computer, from the ground up, around the [Z80](https://en.wikipedia.org/wiki/Zilog_Z80) microprocessor. -I had to learn a wide range of skills for this project, including things like learning how to design PCBs, programming in assembly, working with FPGAs, and learning to operate an oscilloscope. +The first big hardware project that I worked on was building a computer, from the ground up, around the [Z80] microprocessor. +I had to learn a wide range of skills for this project, including things like learning how to design PCBs, programming in assembly, working with [FPGA]s, and learning to operate an oscilloscope. + +[Z80]: https://en.wikipedia.org/wiki/Zilog_Z80 +[FPGA]: https://en.wikipeida.org/wiki/Field-programmable_gate_array ### [Car Stereo](https://git.huizinga.dev/Dreaded_X/car-stereo) -My Peugeot 207 only has bluetooth for calling, so I decided it would be fun to build my own bluetooth receiver using the [ESP32](https://en.wikipedia.org/wiki/ESP32) microcontroller. +My Peugeot 207 only has bluetooth for calling, so I decided it would be fun to build my own bluetooth receiver using the [ESP32] microcontroller. The original goal was to just build an audio receiver and hook it up to the aux port in my glovebox. -However since then I have also connected the ESP32 to the [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) of my car, allowing me to use the controls on my steering wheel to control the music. +However since then I have also connected the [ESP32] to the [CAN bus] of my car, allowing me to use the controls on my steering wheel to control the music. + +[ESP32]: https://en.wikipedia.org/wiki/ESP32 +[CAN bus]: https://en.wikipedia.org/wiki/CAN_bus ### [Home Automation](https://git.huizinga.dev/Dreaded_X/automation_rs) I have slowly been converting my house into my very own smart home! -It all started with a couple of Philips Hue light bulb, the Hue app allows for some level of automation but it wasn't quite doing what I wanted. -So initially I wrote a very simple program in [Go](https://go.dev). +It all started with a couple of Philips Hue light bulbs, the Hue app allows for some level of automation but it wasn't quite doing what I wanted. +So initially I wrote a very simple program in [Go]. As I added more smart devices to my house, the program grew massively in scope with things quickly getting hacked in just to make it work. Eventually I decided to rewrite the whole thing in Rust! -This was my first real Rust after picking up the language during [Advent of Code](https://adventofcode.com/) and was (and still is) a great learning experience. +This was my first real Rust after picking up the language during [Advent of Code] and was (and still is) a great learning experience. + +[Philips Hue]: https://nl.wikipedia.org/wiki/Philips_Hue +[Go]: https://go.dev +[Advent of Code]: https://adventofcode.com/ ### [Pico P1](https://git.huizinga.dev/Dreaded_X/pico_p1) -This is my most recent project, as I had recently decided to pick up a [Raspberry Pi Pico W](https://en.wikipedia.org/wiki/Raspberry_Pi#Raspberry_Pi_Pico) just to play around with. -I decided to build a P1 reader to read out my [DSMR5](https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf) based smart meter. +This is my most recent project, as I had recently decided to pick up a [Raspberry Pi Pico W] just to play around with. +I decided to build a P1 reader to read out my [DSMR5] based smart meter. The main intention of this project is to learn about Rust for embedded devices, which is still a very new ecosystem. So far it has been quite a nice experience! + +[Raspberry Pi Pico W]: https://en.wikipedia.org/wiki/Raspberry_Pi#Raspberry_Pi_Pico +[DSMR5]: https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf + diff --git a/markdown/README.md b/markdown/README.md new file mode 100644 index 0000000..bae741c --- /dev/null +++ b/markdown/README.md @@ -0,0 +1,8 @@ +# Hi! I'm Tim Huizinga +#{blurb.md} + +## Projects +#{project/z80.md} +#{project/car-stereo.md} +#{project/automation.md} +#{project/pico_p1.md} diff --git a/markdown/blurb.md b/markdown/blurb.md new file mode 100644 index 0000000..c6dee07 --- /dev/null +++ b/markdown/blurb.md @@ -0,0 +1,11 @@ +An Applied Physics student with a passion for programming! + +I have always enjoyed programming as a hobby, and would love to make it my carreer. +Since then I have also combining this hobby with the hardware side of things. +Most recently I have picked up [Rust], and have fallen in love with this programming language. + +I'm also quite experienced with Linux as I have been daily driving it for the past decade at this point. +Making me very familiar with the terminal and the different command line tools available. +And have even been running my own Linux server for quite some time now! + +[Rust]: https://rust-lang.org diff --git a/markdown/project/automation.md b/markdown/project/automation.md new file mode 100644 index 0000000..0a06dd2 --- /dev/null +++ b/markdown/project/automation.md @@ -0,0 +1,16 @@ +--- +type = "Project" +url = "git.huizinga.dev/Dreaded_X/automation_rs" +title = "Home Automation" +--- + +I have slowly been converting my house into my very own smart home! +It all started with a couple of Philips Hue light bulbs, the Hue app allows for some level of automation but it wasn't quite doing what I wanted. +So initially I wrote a very simple program in [Go]. +As I added more smart devices to my house, the program grew massively in scope with things quickly getting hacked in just to make it work. +Eventually I decided to rewrite the whole thing in Rust! +This was my first real Rust after picking up the language during [Advent of Code] and was (and still is) a great learning experience. + +[Philips Hue]: https://nl.wikipedia.org/wiki/Philips_Hue +[Go]: https://go.dev +[Advent of Code]: https://adventofcode.com/ diff --git a/markdown/project/car-stereo.md b/markdown/project/car-stereo.md new file mode 100644 index 0000000..c8eef7e --- /dev/null +++ b/markdown/project/car-stereo.md @@ -0,0 +1,12 @@ +--- +type = "Project" +url = "git.huizinga.dev/Dreaded_X/car-stereo" +title = "Car Stereo" +--- + +My Peugeot 207 only has bluetooth for calling, so I decided it would be fun to build my own bluetooth receiver using the [ESP32] microcontroller. +The original goal was to just build an audio receiver and hook it up to the aux port in my glovebox. +However since then I have also connected the [ESP32] to the [CAN bus] of my car, allowing me to use the controls on my steering wheel to control the music. + +[ESP32]: https://en.wikipedia.org/wiki/ESP32 +[CAN bus]: https://en.wikipedia.org/wiki/CAN_bus diff --git a/markdown/project/pico_p1.md b/markdown/project/pico_p1.md new file mode 100644 index 0000000..bb4d334 --- /dev/null +++ b/markdown/project/pico_p1.md @@ -0,0 +1,13 @@ +--- +type = "Project" +url = "git.huizinga.dev/Dreaded_X/pico_p1" +title = "Pico P1" +--- + +This is my most recent project, as I had recently decided to pick up a [Raspberry Pi Pico W] just to play around with. +I decided to build a P1 reader to read out my [DSMR5] based smart meter. +The main intention of this project is to learn about Rust for embedded devices, which is still a very new ecosystem. +So far it has been quite a nice experience! + +[Raspberry Pi Pico W]: https://en.wikipedia.org/wiki/Raspberry_Pi#Raspberry_Pi_Pico +[DSMR5]: https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf diff --git a/markdown/project/z80.md b/markdown/project/z80.md new file mode 100644 index 0000000..e2a43fb --- /dev/null +++ b/markdown/project/z80.md @@ -0,0 +1,11 @@ +--- +type = "Project" +url = "git.huizinga.dev/Z80/Z80" +title = "Z80 Computer" +--- + +The first big hardware project that I worked on was building a computer, from the ground up, around the [Z80] microprocessor. +I had to learn a wide range of skills for this project, including things like learning how to design PCBs, programming in assembly, working with [FPGA]s, and learning to operate an oscilloscope. + +[Z80]: https://en.wikipedia.org/wiki/Zilog_Z80 +[FPGA]: https://en.wikipeida.org/wiki/Field-programmable_gate_array diff --git a/tool/.gitignore b/tool/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/tool/.gitignore @@ -0,0 +1 @@ +/target diff --git a/tool/Cargo.lock b/tool/Cargo.lock new file mode 100644 index 0000000..c95a376 --- /dev/null +++ b/tool/Cargo.lock @@ -0,0 +1,219 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "gray_matter" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cf2fb99fac0b821a4e61c61abff076324bb0e5c3b4a83815bbc3518a38971ad" +dependencies = [ + "serde", + "serde_json", + "toml", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "memchr" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "tool" +version = "0.1.0" +dependencies = [ + "anyhow", + "dotenvy", + "gray_matter", + "regex", + "serde", + "walkdir", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/tool/Cargo.toml b/tool/Cargo.toml new file mode 100644 index 0000000..db0b492 --- /dev/null +++ b/tool/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "tool" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.75" +dotenvy = "0.15.7" +gray_matter = { version = "0.2.6", features = [ + "toml", +], default-features = false } +regex = "1.9.4" +serde = { version = "1.0.188", features = ["derive"] } +walkdir = "2.3.3" diff --git a/tool/src/main.rs b/tool/src/main.rs new file mode 100644 index 0000000..78fcf25 --- /dev/null +++ b/tool/src/main.rs @@ -0,0 +1,120 @@ +use std::{ + fs::{create_dir_all, File}, + io::{Read, Write}, + path::Path, +}; + +use gray_matter::{engine::TOML, Matter}; +use regex::{Captures, Regex}; +use serde::Deserialize; +use walkdir::WalkDir; + +#[derive(Debug, Deserialize)] +#[serde(tag = "type")] +enum FrontMatter { + Project { title: String, url: String }, +} + +fn main() -> anyhow::Result<()> { + dotenvy::dotenv().ok(); + + generate_latex()?; + + generate_readme()?; + + Ok(()) +} + +fn generate_latex() -> anyhow::Result<()> { + let matter = Matter::::new(); + + let prefix = Path::new("../markdown"); + + for entry in WalkDir::new(prefix).into_iter() { + let entry = entry?; + + if entry.metadata()?.is_dir() { + continue; + } + + println!("{entry:#?}"); + + let mut file = File::open(entry.path()).unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + + let result = matter.parse(&contents); + let content = format!( + "\\begin{{markdown}}\n{}\n\\end{{markdown}}\n", + result.content + ); + let contents = if let Some(data) = result.data { + let front_matter: FrontMatter = data.deserialize().expect("Invalid front matter"); + + match front_matter { + FrontMatter::Project { title, url } => { + format!( + "\\cvsect{{{title}}}\n\n{content}\n\n\\vspace{{3pt}}\n\n\\rurl{{{url}}}\n" + ) + } + } + } else { + content + }; + + let path = entry.path().strip_prefix(prefix)?.with_extension("tex"); + let path = Path::new("../latex").join(path); + create_dir_all(path.parent().unwrap())?; + let mut file = File::create(path)?; + file.write_all(contents.as_bytes())?; + } + + let private = format!( + "\\newcommand{{\\city}}{{{}}}\n\\newcommand{{\\phone}}{{{}}}\n\\newcommand{{\\email}}{{{}}}\n", + std::env::var("CITY")?, + std::env::var("PHONE")?, + std::env::var("EMAIL")?, + ); + File::create("../latex/private.tex")?.write_all(private.as_bytes())?; + + Ok(()) +} + +fn generate_readme() -> anyhow::Result<()> { + let readme = "../markdown/README.md"; + let base_path = Path::new(readme).parent().expect("File should have parent"); + + let mut file = File::open(readme)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + + let matter = Matter::::new(); + + let re = Regex::new(r"\#\{(.*)\}").expect("Regex should be valid"); + let contents = re.replace_all(&contents, |caps: &Captures| { + let path = caps.get(1).expect("Capture group should exist").as_str(); + println!("Including '{path}' in README.md"); + + let mut file = File::open(base_path.join(path)).unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + + let result = matter.parse(&contents); + if let Some(data) = result.data { + let front_matter: FrontMatter = data.deserialize().expect("Invalid front matter"); + + match front_matter { + FrontMatter::Project { title, url } => { + format!("### [{title}](https://{url})\n{}\n", result.content) + } + } + } else { + format!("{}\n", result.content) + } + }); + + let mut file = File::create("../README.md")?; + file.write_all(contents.as_bytes()).unwrap(); + + Ok(()) +}