planting a seed
This commit is contained in:
commit
e69dcdc197
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
295
Cargo.lock
generated
Normal file
295
Cargo.lock
generated
Normal file
|
@ -0,0 +1,295 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "4.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[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 = "pulldown-cmark"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
|
||||
|
||||
[[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 = "sha2"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[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 = "thiserror"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "treehouse-format"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "treehouse-incubator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"handlebars",
|
||||
"pulldown-cmark",
|
||||
"thiserror",
|
||||
"treehouse-format",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[workspace]
|
||||
members = ["crates/*"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
treehouse-format = { path = "crates/treehouse-format" }
|
37
content/tree/root.tree
Normal file
37
content/tree/root.tree
Normal file
|
@ -0,0 +1,37 @@
|
|||
- # treehouse
|
||||
|
||||
- welcome to treehouse!
|
||||
|
||||
- treehouse is a brand new static website generator, inspired by the likes of Jekyll and Hugo, but offering a writing experience more close to Logseq
|
||||
|
||||
- ie. a public braindump
|
||||
|
||||
- since you're here, you're probably just setting up
|
||||
|
||||
- i'd highly recommend familiarizing yourself with the syntax by visiting `content/tree/root.tree`
|
||||
|
||||
- this special file is almost like your index.html
|
||||
|
||||
+ the syntax is pretty simple
|
||||
|
||||
- separate blocks are delimited with a blank line
|
||||
|
||||
- the indentation level (number of spaces) decides how nested the block is
|
||||
|
||||
- the exact amount doesn't matter, just that more nested blocks must have more spaces before them than their parents
|
||||
|
||||
- also blocks on the same level must be indented with the same number of spaces but that's hopefully pretty obvious
|
||||
|
||||
+ the block content begins with a dash `-` or a plus `+`
|
||||
|
||||
- a dash `-` means that the block is open by default
|
||||
|
||||
- a plus `+` means that the block is hidden by default
|
||||
|
||||
- before the block content, there can be an arbitrary amount of TOML specifying the block config
|
||||
|
||||
- many keys are available but they aren't really documented outside of code
|
||||
|
||||
- blocks can span multiple lines as long as they are not broken apart with a blank line
|
||||
|
||||
- that means each block can contain at most one paragraph, unless you use dirty HTML hacks (cheater!)
|
7
crates/treehouse-format/Cargo.toml
Normal file
7
crates/treehouse-format/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "treehouse-format"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.47"
|
113
crates/treehouse-format/src/lib.rs
Normal file
113
crates/treehouse-format/src/lib.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use std::ops::Range;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BranchKind {
|
||||
/// Expanded by default.
|
||||
Expanded,
|
||||
/// Folded by default.
|
||||
Collapsed,
|
||||
}
|
||||
|
||||
impl BranchKind {
|
||||
pub fn char(&self) -> char {
|
||||
match self {
|
||||
BranchKind::Expanded => '-',
|
||||
BranchKind::Collapsed => '+',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Branch {
|
||||
pub indent_level: usize,
|
||||
pub config: Range<usize>,
|
||||
pub kind: BranchKind,
|
||||
pub content: Range<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Parser<'a> {
|
||||
pub input: &'a str,
|
||||
pub position: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
|
||||
pub enum ParseErrorKind {
|
||||
#[error("branch kind (`+` or `-`) expected")]
|
||||
BranchKindExpected,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
|
||||
#[error("{range:?}: {kind}")]
|
||||
pub struct ParseError {
|
||||
pub kind: ParseErrorKind,
|
||||
pub range: Range<usize>,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn current(&self) -> Option<char> {
|
||||
self.input[self.position..].chars().next()
|
||||
}
|
||||
|
||||
fn advance(&mut self) {
|
||||
self.position += self.current().map(|c| c.len_utf8()).unwrap_or(0);
|
||||
}
|
||||
|
||||
fn eat_as_long_as(&mut self, c: char) -> usize {
|
||||
let mut count = 0;
|
||||
while self.current() == Some(c) {
|
||||
count += 1;
|
||||
self.advance();
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn eat_until(&mut self, c: char) {
|
||||
while self.current() != Some(c) {
|
||||
self.advance();
|
||||
}
|
||||
self.advance();
|
||||
}
|
||||
|
||||
pub fn next_branch(&mut self) -> Result<Option<Branch>, ParseError> {
|
||||
if self.current().is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let indent_level = self.eat_as_long_as(' ');
|
||||
|
||||
// TODO: Configs
|
||||
let config_start = self.position;
|
||||
let config_end = self.position;
|
||||
|
||||
let branch_kind_start = self.position;
|
||||
let branch_kind = match self.current() {
|
||||
Some('-') => BranchKind::Expanded,
|
||||
Some('+') => BranchKind::Collapsed,
|
||||
_ => {
|
||||
return Err(ParseError {
|
||||
kind: ParseErrorKind::BranchKindExpected,
|
||||
range: branch_kind_start..branch_kind_start + 1,
|
||||
})
|
||||
}
|
||||
};
|
||||
self.advance();
|
||||
|
||||
let content_start = self.position;
|
||||
loop {
|
||||
self.eat_until('\n');
|
||||
if let Some('\n') | None = self.current() {
|
||||
self.advance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
let content_end = self.position;
|
||||
|
||||
Ok(Some(Branch {
|
||||
indent_level,
|
||||
config: config_start..config_end,
|
||||
kind: branch_kind,
|
||||
content: content_start..content_end,
|
||||
}))
|
||||
}
|
||||
}
|
11
crates/treehouse-incubator/Cargo.toml
Normal file
11
crates/treehouse-incubator/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "treehouse-incubator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
handlebars = "4.3.7"
|
||||
pulldown-cmark = { version = "0.9.3", default-features = false }
|
||||
thiserror = "1.0.47"
|
||||
treehouse-format = { workspace = true }
|
||||
|
45
crates/treehouse-incubator/src/main.rs
Normal file
45
crates/treehouse-incubator/src/main.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use tree_html::HtmlGenerator;
|
||||
|
||||
mod tree_html;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum Error {
|
||||
#[error("I/O error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("treehouse parsing error: {0}")]
|
||||
Parse(#[from] treehouse_format::ParseError),
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let _ = std::fs::remove_dir_all("target/site");
|
||||
std::fs::create_dir_all("target/site")?;
|
||||
|
||||
let root_file = std::fs::read_to_string("content/tree/root.tree")?;
|
||||
|
||||
let mut parser = treehouse_format::Parser {
|
||||
input: &root_file,
|
||||
position: 0,
|
||||
};
|
||||
let mut generator = HtmlGenerator::default();
|
||||
while let Some(branch) = parser.next_branch()? {
|
||||
for _ in 0..branch.indent_level {
|
||||
print!(" ");
|
||||
}
|
||||
println!(
|
||||
"{} {:?}",
|
||||
branch.kind.char(),
|
||||
&root_file[branch.content.clone()]
|
||||
);
|
||||
generator.add(&root_file, &branch);
|
||||
}
|
||||
std::fs::write(
|
||||
"target/site/index.html",
|
||||
format!(
|
||||
"<!DOCTYPE html><html><head></head><body>{}</body></html>",
|
||||
generator.finish()
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
30
crates/treehouse-incubator/src/tree_html.rs
Normal file
30
crates/treehouse-incubator/src/tree_html.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use treehouse_format::Branch;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct HtmlGenerator {
|
||||
buffer: String,
|
||||
indent_level_stack: Vec<usize>,
|
||||
}
|
||||
|
||||
impl HtmlGenerator {
|
||||
pub fn add(&mut self, source: &str, branch: &Branch) {
|
||||
if Some(&branch.indent_level) > self.indent_level_stack.last() {
|
||||
self.indent_level_stack.push(branch.indent_level);
|
||||
self.buffer.push_str("<ul>");
|
||||
}
|
||||
while Some(&branch.indent_level) < self.indent_level_stack.last() {
|
||||
self.indent_level_stack.pop();
|
||||
self.buffer.push_str("</ul>");
|
||||
}
|
||||
self.buffer.push_str("<li>");
|
||||
self.buffer.push_str(&source[branch.content.clone()]);
|
||||
self.buffer.push_str("</li>");
|
||||
}
|
||||
|
||||
pub fn finish(mut self) -> String {
|
||||
for _ in self.indent_level_stack.drain(..) {
|
||||
self.buffer.push_str("</ul>");
|
||||
}
|
||||
self.buffer
|
||||
}
|
||||
}
|
13
static/index.hbs
Normal file
13
static/index.hbs
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{{ config.treehouse.title }}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{ tree }}
|
||||
</body>
|
||||
|
||||
</html>
|
3
treehouse.toml
Normal file
3
treehouse.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[treehouse]
|
||||
title = "treehouse"
|
||||
author = "liquidex"
|
Loading…
Reference in a new issue