From b792688776899fa254f94c43ced90d04d5d2b251 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=83=AA=E3=82=AD=E8=90=8C?=
Date: Thu, 10 Jul 2025 16:50:41 +0200
Subject: [PATCH 1/4] remove treehouse-format crate and collapse everything
into src
---
Cargo.lock | 37 +++++++++++------
Cargo.toml | 38 +++++++++++++++---
crates/treehouse-format/Cargo.toml | 7 ----
crates/treehouse-format/src/lib.rs | 32 ---------------
crates/treehouse/Cargo.toml | 36 -----------------
{crates/treehouse/src => src}/cli.rs | 0
{crates/treehouse/src => src}/cli/fix.rs | 2 +-
{crates/treehouse/src => src}/cli/serve.rs | 0
.../src => src}/cli/serve/live_reload.rs | 0
.../src => src}/cli/serve/picture_upload.rs | 0
{crates/treehouse/src => src}/cli/wc.rs | 3 +-
{crates/treehouse/src => src}/config.rs | 0
{crates/treehouse/src => src}/dirs.rs | 0
{crates/treehouse/src => src}/fun.rs | 0
{crates/treehouse/src => src}/fun/seasons.rs | 0
{crates/treehouse/src => src}/generate.rs | 0
.../treehouse/src => src}/generate/atom.rs | 0
.../src => src}/generate/dir_helper.rs | 0
.../generate/include_static_helper.rs | 0
.../src => src}/generate/simple_template.rs | 0
.../treehouse/src => src}/generate/tree.rs | 0
{crates/treehouse/src => src}/history.rs | 0
{crates/treehouse/src => src}/html.rs | 0
.../treehouse/src => src}/html/breadcrumbs.rs | 0
{crates/treehouse/src => src}/html/djot.rs | 0
.../treehouse/src => src}/html/highlight.rs | 0
.../src => src}/html/highlight/compiled.rs | 0
.../src => src}/html/highlight/tokenize.rs | 0
{crates/treehouse/src => src}/html/navmap.rs | 0
{crates/treehouse/src => src}/html/tree.rs | 5 ++-
{crates/treehouse/src => src}/import_map.rs | 0
{crates/treehouse/src => src}/lib.rs | 0
{crates/treehouse/src => src}/main.rs | 0
{crates/treehouse/src => src}/parse.rs | 8 ++--
{crates/treehouse/src => src}/paths.rs | 0
{crates/treehouse/src => src}/sources.rs | 0
{crates/treehouse/src => src}/state.rs | 0
{crates/treehouse/src => src}/tree.rs | 40 ++++++++++++++++---
.../treehouse-format/src => src/tree}/ast.rs | 2 +-
.../treehouse/src => src}/tree/attributes.rs | 0
src/tree/lib.rs | 1 +
.../src => src}/tree/mini_template.rs | 0
.../treehouse-format/src => src/tree}/pull.rs | 2 +-
{crates/treehouse/src => src}/vfs.rs | 0
{crates/treehouse/src => src}/vfs/anchored.rs | 0
{crates/treehouse/src => src}/vfs/asynch.rs | 0
{crates/treehouse/src => src}/vfs/cd.rs | 0
.../src => src}/vfs/content_cache.rs | 0
.../src => src}/vfs/content_version_cache.rs | 0
{crates/treehouse/src => src}/vfs/edit.rs | 0
{crates/treehouse/src => src}/vfs/file.rs | 0
.../src => src}/vfs/html_canonicalize.rs | 0
.../src => src}/vfs/image_size_cache.rs | 0
{crates/treehouse/src => src}/vfs/mem_dir.rs | 0
{crates/treehouse/src => src}/vfs/overlay.rs | 0
{crates/treehouse/src => src}/vfs/path.rs | 0
{crates/treehouse/src => src}/vfs/physical.rs | 0
static/css/main.css | 9 +++--
template/_doc.hbs | 35 ++++++++++++++++
{crates/treehouse/tests => tests}/it/main.rs | 0
{crates/treehouse/tests => tests}/it/vfs.rs | 0
.../treehouse/tests => tests}/it/vfs/cd.rs | 0
.../treehouse/tests => tests}/it/vfs/file.rs | 0
.../tests => tests}/it/vfs/mount_points.rs | 0
.../tests => tests}/it/vfs/physical.rs | 0
.../tests => tests}/it/vfs_physical/test.txt | 0
66 files changed, 145 insertions(+), 112 deletions(-)
delete mode 100644 crates/treehouse-format/Cargo.toml
delete mode 100644 crates/treehouse-format/src/lib.rs
delete mode 100644 crates/treehouse/Cargo.toml
rename {crates/treehouse/src => src}/cli.rs (100%)
rename {crates/treehouse/src => src}/cli/fix.rs (99%)
rename {crates/treehouse/src => src}/cli/serve.rs (100%)
rename {crates/treehouse/src => src}/cli/serve/live_reload.rs (100%)
rename {crates/treehouse/src => src}/cli/serve/picture_upload.rs (100%)
rename {crates/treehouse/src => src}/cli/wc.rs (97%)
rename {crates/treehouse/src => src}/config.rs (100%)
rename {crates/treehouse/src => src}/dirs.rs (100%)
rename {crates/treehouse/src => src}/fun.rs (100%)
rename {crates/treehouse/src => src}/fun/seasons.rs (100%)
rename {crates/treehouse/src => src}/generate.rs (100%)
rename {crates/treehouse/src => src}/generate/atom.rs (100%)
rename {crates/treehouse/src => src}/generate/dir_helper.rs (100%)
rename {crates/treehouse/src => src}/generate/include_static_helper.rs (100%)
rename {crates/treehouse/src => src}/generate/simple_template.rs (100%)
rename {crates/treehouse/src => src}/generate/tree.rs (100%)
rename {crates/treehouse/src => src}/history.rs (100%)
rename {crates/treehouse/src => src}/html.rs (100%)
rename {crates/treehouse/src => src}/html/breadcrumbs.rs (100%)
rename {crates/treehouse/src => src}/html/djot.rs (100%)
rename {crates/treehouse/src => src}/html/highlight.rs (100%)
rename {crates/treehouse/src => src}/html/highlight/compiled.rs (100%)
rename {crates/treehouse/src => src}/html/highlight/tokenize.rs (100%)
rename {crates/treehouse/src => src}/html/navmap.rs (100%)
rename {crates/treehouse/src => src}/html/tree.rs (99%)
rename {crates/treehouse/src => src}/import_map.rs (100%)
rename {crates/treehouse/src => src}/lib.rs (100%)
rename {crates/treehouse/src => src}/main.rs (100%)
rename {crates/treehouse/src => src}/parse.rs (85%)
rename {crates/treehouse/src => src}/paths.rs (100%)
rename {crates/treehouse/src => src}/sources.rs (100%)
rename {crates/treehouse/src => src}/state.rs (100%)
rename {crates/treehouse/src => src}/tree.rs (94%)
rename {crates/treehouse-format/src => src/tree}/ast.rs (99%)
rename {crates/treehouse/src => src}/tree/attributes.rs (100%)
create mode 100644 src/tree/lib.rs
rename {crates/treehouse/src => src}/tree/mini_template.rs (100%)
rename {crates/treehouse-format/src => src/tree}/pull.rs (99%)
rename {crates/treehouse/src => src}/vfs.rs (100%)
rename {crates/treehouse/src => src}/vfs/anchored.rs (100%)
rename {crates/treehouse/src => src}/vfs/asynch.rs (100%)
rename {crates/treehouse/src => src}/vfs/cd.rs (100%)
rename {crates/treehouse/src => src}/vfs/content_cache.rs (100%)
rename {crates/treehouse/src => src}/vfs/content_version_cache.rs (100%)
rename {crates/treehouse/src => src}/vfs/edit.rs (100%)
rename {crates/treehouse/src => src}/vfs/file.rs (100%)
rename {crates/treehouse/src => src}/vfs/html_canonicalize.rs (100%)
rename {crates/treehouse/src => src}/vfs/image_size_cache.rs (100%)
rename {crates/treehouse/src => src}/vfs/mem_dir.rs (100%)
rename {crates/treehouse/src => src}/vfs/overlay.rs (100%)
rename {crates/treehouse/src => src}/vfs/path.rs (100%)
rename {crates/treehouse/src => src}/vfs/physical.rs (100%)
create mode 100644 template/_doc.hbs
rename {crates/treehouse/tests => tests}/it/main.rs (100%)
rename {crates/treehouse/tests => tests}/it/vfs.rs (100%)
rename {crates/treehouse/tests => tests}/it/vfs/cd.rs (100%)
rename {crates/treehouse/tests => tests}/it/vfs/file.rs (100%)
rename {crates/treehouse/tests => tests}/it/vfs/mount_points.rs (100%)
rename {crates/treehouse/tests => tests}/it/vfs/physical.rs (100%)
rename {crates/treehouse/tests => tests}/it/vfs_physical/test.txt (100%)
diff --git a/Cargo.lock b/Cargo.lock
index 5f8e6a8..e89722b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -724,7 +724,7 @@ dependencies = [
"pest_derive",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -1409,7 +1409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
dependencies = [
"memchr",
- "thiserror",
+ "thiserror 1.0.69",
"ucd-trie",
]
@@ -1599,7 +1599,7 @@ dependencies = [
"rand_chacha",
"simd_helpers",
"system-deps",
- "thiserror",
+ "thiserror 1.0.69",
"v_frame",
"wasm-bindgen",
]
@@ -1931,7 +1931,16 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl 2.0.12",
]
[[package]]
@@ -1945,6 +1954,17 @@ dependencies = [
"syn",
]
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "thread_local"
version = "1.1.8"
@@ -2176,24 +2196,17 @@ dependencies = [
"regex",
"serde",
"serde_json",
+ "thiserror 2.0.12",
"tokio",
"toml_edit 0.19.15",
"tracing",
"tracing-chrome",
"tracing-subscriber",
- "treehouse-format",
"ulid",
"webp",
"xmlparser",
]
-[[package]]
-name = "treehouse-format"
-version = "0.1.0"
-dependencies = [
- "thiserror",
-]
-
[[package]]
name = "typenum"
version = "1.17.0"
diff --git a/Cargo.toml b/Cargo.toml
index 9c407e9..97f0b1b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,11 +1,37 @@
-[workspace]
-members = ["crates/*"]
-resolver = "2"
+[package]
+name = "treehouse"
+version = "0.1.0"
+edition = "2021"
-[workspace.dependencies]
+[dependencies]
+anyhow = "1.0.75"
+axum = { version = "0.7.9", features = ["macros"] }
+axum-macros = "0.4.2"
+base64 = "0.21.7"
+blake3 = "1.5.3"
+chrono = { version = "0.4.35", features = ["serde"] }
+clap = { version = "4.3.22", features = ["derive"] }
+codespan-reporting = "0.11.1"
+dashmap = "6.1.0"
+git2 = { version = "0.19.0", default-features = false, features = ["vendored-libgit2"] }
+handlebars = "4.3.7"
+image = "0.25.5"
+indexmap = { version = "2.2.6", features = ["serde"] }
+jotdown = { version = "0.4.1", default-features = false }
+rand = "0.8.5"
+rayon = "1.10.0"
+regex = "1.10.3"
+serde = { version = "1.0.183", features = ["derive"] }
+serde_json = "1.0.105"
+thiserror = "2.0.12"
+tokio = { version = "1.32.0", features = ["full"] }
+toml_edit = { version = "0.19.14", features = ["serde"] }
tracing = "0.1.40"
-
-treehouse-format = { path = "crates/treehouse-format" }
+tracing-chrome = "0.7.2"
+tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
+ulid = "1.0.0"
+webp = "0.3.0"
+xmlparser = "0.13.6"
[profile.dev]
package.webp.opt-level = 3
diff --git a/crates/treehouse-format/Cargo.toml b/crates/treehouse-format/Cargo.toml
deleted file mode 100644
index 7db6b26..0000000
--- a/crates/treehouse-format/Cargo.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-[package]
-name = "treehouse-format"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-thiserror = "1.0.47"
diff --git a/crates/treehouse-format/src/lib.rs b/crates/treehouse-format/src/lib.rs
deleted file mode 100644
index 6afdf89..0000000
--- a/crates/treehouse-format/src/lib.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use std::ops::Range;
-
-pub mod ast;
-pub mod pull;
-
-#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
-pub enum ParseErrorKind {
- #[error("branch kind (`+` or `-`) expected")]
- BranchKindExpected,
-
- #[error("root branches must not be indented")]
- RootIndentLevel,
-
- #[error("at least {expected} spaces of indentation were expected, but got {got}")]
- InconsistentIndentation { got: usize, expected: usize },
-
- #[error("unterminated code block")]
- UnterminatedCodeBlock,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
-#[error("{range:?}: {kind}")]
-pub struct ParseError {
- pub kind: ParseErrorKind,
- pub range: Range,
-}
-
-impl ParseErrorKind {
- pub fn at(self, range: Range) -> ParseError {
- ParseError { kind: self, range }
- }
-}
diff --git a/crates/treehouse/Cargo.toml b/crates/treehouse/Cargo.toml
deleted file mode 100644
index 2198fdf..0000000
--- a/crates/treehouse/Cargo.toml
+++ /dev/null
@@ -1,36 +0,0 @@
-[package]
-name = "treehouse"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-
-treehouse-format = { workspace = true }
-
-anyhow = "1.0.75"
-axum = { version = "0.7.9", features = ["macros"] }
-axum-macros = "0.4.2"
-base64 = "0.21.7"
-blake3 = "1.5.3"
-chrono = { version = "0.4.35", features = ["serde"] }
-clap = { version = "4.3.22", features = ["derive"] }
-codespan-reporting = "0.11.1"
-dashmap = "6.1.0"
-git2 = { version = "0.19.0", default-features = false, features = ["vendored-libgit2"] }
-handlebars = "4.3.7"
-image = "0.25.5"
-indexmap = { version = "2.2.6", features = ["serde"] }
-jotdown = { version = "0.4.1", default-features = false }
-rand = "0.8.5"
-rayon = "1.10.0"
-regex = "1.10.3"
-serde = { version = "1.0.183", features = ["derive"] }
-serde_json = "1.0.105"
-tokio = { version = "1.32.0", features = ["full"] }
-toml_edit = { version = "0.19.14", features = ["serde"] }
-tracing.workspace = true
-tracing-chrome = "0.7.2"
-tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
-ulid = "1.0.0"
-webp = "0.3.0"
-xmlparser = "0.13.6"
diff --git a/crates/treehouse/src/cli.rs b/src/cli.rs
similarity index 100%
rename from crates/treehouse/src/cli.rs
rename to src/cli.rs
diff --git a/crates/treehouse/src/cli/fix.rs b/src/cli/fix.rs
similarity index 99%
rename from crates/treehouse/src/cli/fix.rs
rename to src/cli/fix.rs
index b5e1342..6e64cc0 100644
--- a/crates/treehouse/src/cli/fix.rs
+++ b/src/cli/fix.rs
@@ -3,11 +3,11 @@ use std::ops::{ControlFlow, Range};
use anyhow::{anyhow, Context};
use codespan_reporting::diagnostic::Diagnostic;
use tracing::{error, info};
-use treehouse_format::ast::Branch;
use crate::{
parse::{self, parse_toml_with_diagnostics, parse_tree_with_diagnostics},
state::{report_diagnostics, FileId, Source, Treehouse},
+ tree::ast::Branch,
vfs::{self, Content, Dir, Edit, EditPath, VPath},
};
diff --git a/crates/treehouse/src/cli/serve.rs b/src/cli/serve.rs
similarity index 100%
rename from crates/treehouse/src/cli/serve.rs
rename to src/cli/serve.rs
diff --git a/crates/treehouse/src/cli/serve/live_reload.rs b/src/cli/serve/live_reload.rs
similarity index 100%
rename from crates/treehouse/src/cli/serve/live_reload.rs
rename to src/cli/serve/live_reload.rs
diff --git a/crates/treehouse/src/cli/serve/picture_upload.rs b/src/cli/serve/picture_upload.rs
similarity index 100%
rename from crates/treehouse/src/cli/serve/picture_upload.rs
rename to src/cli/serve/picture_upload.rs
diff --git a/crates/treehouse/src/cli/wc.rs b/src/cli/wc.rs
similarity index 97%
rename from crates/treehouse/src/cli/wc.rs
rename to src/cli/wc.rs
index b210225..7028dc3 100644
--- a/crates/treehouse/src/cli/wc.rs
+++ b/src/cli/wc.rs
@@ -1,10 +1,9 @@
use std::ops::ControlFlow;
-use treehouse_format::ast::{Branch, Roots};
-
use crate::{
parse::parse_tree_with_diagnostics,
state::{report_diagnostics, Source, Treehouse},
+ tree::ast::{Branch, Roots},
vfs::{self, Content, Dir, VPath},
};
diff --git a/crates/treehouse/src/config.rs b/src/config.rs
similarity index 100%
rename from crates/treehouse/src/config.rs
rename to src/config.rs
diff --git a/crates/treehouse/src/dirs.rs b/src/dirs.rs
similarity index 100%
rename from crates/treehouse/src/dirs.rs
rename to src/dirs.rs
diff --git a/crates/treehouse/src/fun.rs b/src/fun.rs
similarity index 100%
rename from crates/treehouse/src/fun.rs
rename to src/fun.rs
diff --git a/crates/treehouse/src/fun/seasons.rs b/src/fun/seasons.rs
similarity index 100%
rename from crates/treehouse/src/fun/seasons.rs
rename to src/fun/seasons.rs
diff --git a/crates/treehouse/src/generate.rs b/src/generate.rs
similarity index 100%
rename from crates/treehouse/src/generate.rs
rename to src/generate.rs
diff --git a/crates/treehouse/src/generate/atom.rs b/src/generate/atom.rs
similarity index 100%
rename from crates/treehouse/src/generate/atom.rs
rename to src/generate/atom.rs
diff --git a/crates/treehouse/src/generate/dir_helper.rs b/src/generate/dir_helper.rs
similarity index 100%
rename from crates/treehouse/src/generate/dir_helper.rs
rename to src/generate/dir_helper.rs
diff --git a/crates/treehouse/src/generate/include_static_helper.rs b/src/generate/include_static_helper.rs
similarity index 100%
rename from crates/treehouse/src/generate/include_static_helper.rs
rename to src/generate/include_static_helper.rs
diff --git a/crates/treehouse/src/generate/simple_template.rs b/src/generate/simple_template.rs
similarity index 100%
rename from crates/treehouse/src/generate/simple_template.rs
rename to src/generate/simple_template.rs
diff --git a/crates/treehouse/src/generate/tree.rs b/src/generate/tree.rs
similarity index 100%
rename from crates/treehouse/src/generate/tree.rs
rename to src/generate/tree.rs
diff --git a/crates/treehouse/src/history.rs b/src/history.rs
similarity index 100%
rename from crates/treehouse/src/history.rs
rename to src/history.rs
diff --git a/crates/treehouse/src/html.rs b/src/html.rs
similarity index 100%
rename from crates/treehouse/src/html.rs
rename to src/html.rs
diff --git a/crates/treehouse/src/html/breadcrumbs.rs b/src/html/breadcrumbs.rs
similarity index 100%
rename from crates/treehouse/src/html/breadcrumbs.rs
rename to src/html/breadcrumbs.rs
diff --git a/crates/treehouse/src/html/djot.rs b/src/html/djot.rs
similarity index 100%
rename from crates/treehouse/src/html/djot.rs
rename to src/html/djot.rs
diff --git a/crates/treehouse/src/html/highlight.rs b/src/html/highlight.rs
similarity index 100%
rename from crates/treehouse/src/html/highlight.rs
rename to src/html/highlight.rs
diff --git a/crates/treehouse/src/html/highlight/compiled.rs b/src/html/highlight/compiled.rs
similarity index 100%
rename from crates/treehouse/src/html/highlight/compiled.rs
rename to src/html/highlight/compiled.rs
diff --git a/crates/treehouse/src/html/highlight/tokenize.rs b/src/html/highlight/tokenize.rs
similarity index 100%
rename from crates/treehouse/src/html/highlight/tokenize.rs
rename to src/html/highlight/tokenize.rs
diff --git a/crates/treehouse/src/html/navmap.rs b/src/html/navmap.rs
similarity index 100%
rename from crates/treehouse/src/html/navmap.rs
rename to src/html/navmap.rs
diff --git a/crates/treehouse/src/html/tree.rs b/src/html/tree.rs
similarity index 99%
rename from crates/treehouse/src/html/tree.rs
rename to src/html/tree.rs
index 7453bb5..a574e39 100644
--- a/crates/treehouse/src/html/tree.rs
+++ b/src/html/tree.rs
@@ -1,7 +1,6 @@
use std::fmt::Write;
use chrono::{DateTime, Utc};
-use treehouse_format::pull::BranchKind;
use crate::{
config::Config,
@@ -11,7 +10,9 @@ use crate::{
state::{FileId, Treehouse},
tree::{
attributes::{Content, Stage, Visibility},
- mini_template, SemaBranchId,
+ mini_template,
+ pull::BranchKind,
+ SemaBranchId,
},
vfs::{self, VPath, VPathBuf},
};
diff --git a/crates/treehouse/src/import_map.rs b/src/import_map.rs
similarity index 100%
rename from crates/treehouse/src/import_map.rs
rename to src/import_map.rs
diff --git a/crates/treehouse/src/lib.rs b/src/lib.rs
similarity index 100%
rename from crates/treehouse/src/lib.rs
rename to src/lib.rs
diff --git a/crates/treehouse/src/main.rs b/src/main.rs
similarity index 100%
rename from crates/treehouse/src/main.rs
rename to src/main.rs
diff --git a/crates/treehouse/src/parse.rs b/src/parse.rs
similarity index 85%
rename from crates/treehouse/src/parse.rs
rename to src/parse.rs
index 56fe2f4..e24bcbe 100644
--- a/crates/treehouse/src/parse.rs
+++ b/src/parse.rs
@@ -2,9 +2,11 @@ use std::{ops::Range, str::FromStr};
use codespan_reporting::diagnostic::{Diagnostic, Label, LabelStyle, Severity};
use tracing::instrument;
-use treehouse_format::ast::Roots;
-use crate::state::{toml_error_to_diagnostic, FileId, TomlError, Treehouse};
+use crate::{
+ state::{toml_error_to_diagnostic, FileId, TomlError, Treehouse},
+ tree::{self, ast::Roots},
+};
pub struct ErrorsEmitted;
@@ -13,7 +15,7 @@ pub fn parse_tree_with_diagnostics(
file_id: FileId,
input: &str,
) -> Result>> {
- Roots::parse(&mut treehouse_format::pull::Parser { input, position: 0 }).map_err(|error| {
+ Roots::parse(&mut tree::pull::Parser { input, position: 0 }).map_err(|error| {
vec![Diagnostic {
severity: Severity::Error,
code: Some("tree".into()),
diff --git a/crates/treehouse/src/paths.rs b/src/paths.rs
similarity index 100%
rename from crates/treehouse/src/paths.rs
rename to src/paths.rs
diff --git a/crates/treehouse/src/sources.rs b/src/sources.rs
similarity index 100%
rename from crates/treehouse/src/sources.rs
rename to src/sources.rs
diff --git a/crates/treehouse/src/state.rs b/src/state.rs
similarity index 100%
rename from crates/treehouse/src/state.rs
rename to src/state.rs
diff --git a/crates/treehouse/src/tree.rs b/src/tree.rs
similarity index 94%
rename from crates/treehouse/src/tree.rs
rename to src/tree.rs
index 6c3bd9d..b922e32 100644
--- a/crates/treehouse/src/tree.rs
+++ b/src/tree.rs
@@ -1,20 +1,22 @@
+pub mod ast;
pub mod attributes;
pub mod mini_template;
+pub mod pull;
use std::ops::Range;
use attributes::Timestamps;
use codespan_reporting::diagnostic::{Diagnostic, Label, LabelStyle, Severity};
use tracing::instrument;
-use treehouse_format::{
- ast::{Branch, Roots},
- pull::BranchKind,
-};
use crate::{
config::Config,
state::{toml_error_to_diagnostic, FileId, Source, TomlError, Treehouse},
- tree::attributes::{Attributes, Content},
+ tree::{
+ ast::{Branch, Roots},
+ attributes::{Attributes, Content},
+ pull::BranchKind,
+ },
};
use self::attributes::RootAttributes;
@@ -409,3 +411,31 @@ impl SemaBranch {
attributes
}
}
+
+#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
+pub enum ParseErrorKind {
+ #[error("branch kind (`+` or `-`) expected")]
+ BranchKindExpected,
+
+ #[error("root branches must not be indented")]
+ RootIndentLevel,
+
+ #[error("at least {expected} spaces of indentation were expected, but got {got}")]
+ InconsistentIndentation { got: usize, expected: usize },
+
+ #[error("unterminated code block")]
+ UnterminatedCodeBlock,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
+#[error("{range:?}: {kind}")]
+pub struct ParseError {
+ pub kind: ParseErrorKind,
+ pub range: Range,
+}
+
+impl ParseErrorKind {
+ pub fn at(self, range: Range) -> ParseError {
+ ParseError { kind: self, range }
+ }
+}
diff --git a/crates/treehouse-format/src/ast.rs b/src/tree/ast.rs
similarity index 99%
rename from crates/treehouse-format/src/ast.rs
rename to src/tree/ast.rs
index e8e4915..5c97879 100644
--- a/crates/treehouse-format/src/ast.rs
+++ b/src/tree/ast.rs
@@ -1,6 +1,6 @@
use std::ops::Range;
-use crate::{
+use super::{
pull::{Attributes, BranchEvent, BranchKind, Parser},
ParseError, ParseErrorKind,
};
diff --git a/crates/treehouse/src/tree/attributes.rs b/src/tree/attributes.rs
similarity index 100%
rename from crates/treehouse/src/tree/attributes.rs
rename to src/tree/attributes.rs
diff --git a/src/tree/lib.rs b/src/tree/lib.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/tree/lib.rs
@@ -0,0 +1 @@
+
diff --git a/crates/treehouse/src/tree/mini_template.rs b/src/tree/mini_template.rs
similarity index 100%
rename from crates/treehouse/src/tree/mini_template.rs
rename to src/tree/mini_template.rs
diff --git a/crates/treehouse-format/src/pull.rs b/src/tree/pull.rs
similarity index 99%
rename from crates/treehouse-format/src/pull.rs
rename to src/tree/pull.rs
index 964ca4e..c1e4fd6 100644
--- a/crates/treehouse-format/src/pull.rs
+++ b/src/tree/pull.rs
@@ -1,6 +1,6 @@
use std::{convert::identity, ops::Range};
-use crate::{ParseError, ParseErrorKind};
+use super::{ParseError, ParseErrorKind};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BranchKind {
diff --git a/crates/treehouse/src/vfs.rs b/src/vfs.rs
similarity index 100%
rename from crates/treehouse/src/vfs.rs
rename to src/vfs.rs
diff --git a/crates/treehouse/src/vfs/anchored.rs b/src/vfs/anchored.rs
similarity index 100%
rename from crates/treehouse/src/vfs/anchored.rs
rename to src/vfs/anchored.rs
diff --git a/crates/treehouse/src/vfs/asynch.rs b/src/vfs/asynch.rs
similarity index 100%
rename from crates/treehouse/src/vfs/asynch.rs
rename to src/vfs/asynch.rs
diff --git a/crates/treehouse/src/vfs/cd.rs b/src/vfs/cd.rs
similarity index 100%
rename from crates/treehouse/src/vfs/cd.rs
rename to src/vfs/cd.rs
diff --git a/crates/treehouse/src/vfs/content_cache.rs b/src/vfs/content_cache.rs
similarity index 100%
rename from crates/treehouse/src/vfs/content_cache.rs
rename to src/vfs/content_cache.rs
diff --git a/crates/treehouse/src/vfs/content_version_cache.rs b/src/vfs/content_version_cache.rs
similarity index 100%
rename from crates/treehouse/src/vfs/content_version_cache.rs
rename to src/vfs/content_version_cache.rs
diff --git a/crates/treehouse/src/vfs/edit.rs b/src/vfs/edit.rs
similarity index 100%
rename from crates/treehouse/src/vfs/edit.rs
rename to src/vfs/edit.rs
diff --git a/crates/treehouse/src/vfs/file.rs b/src/vfs/file.rs
similarity index 100%
rename from crates/treehouse/src/vfs/file.rs
rename to src/vfs/file.rs
diff --git a/crates/treehouse/src/vfs/html_canonicalize.rs b/src/vfs/html_canonicalize.rs
similarity index 100%
rename from crates/treehouse/src/vfs/html_canonicalize.rs
rename to src/vfs/html_canonicalize.rs
diff --git a/crates/treehouse/src/vfs/image_size_cache.rs b/src/vfs/image_size_cache.rs
similarity index 100%
rename from crates/treehouse/src/vfs/image_size_cache.rs
rename to src/vfs/image_size_cache.rs
diff --git a/crates/treehouse/src/vfs/mem_dir.rs b/src/vfs/mem_dir.rs
similarity index 100%
rename from crates/treehouse/src/vfs/mem_dir.rs
rename to src/vfs/mem_dir.rs
diff --git a/crates/treehouse/src/vfs/overlay.rs b/src/vfs/overlay.rs
similarity index 100%
rename from crates/treehouse/src/vfs/overlay.rs
rename to src/vfs/overlay.rs
diff --git a/crates/treehouse/src/vfs/path.rs b/src/vfs/path.rs
similarity index 100%
rename from crates/treehouse/src/vfs/path.rs
rename to src/vfs/path.rs
diff --git a/crates/treehouse/src/vfs/physical.rs b/src/vfs/physical.rs
similarity index 100%
rename from crates/treehouse/src/vfs/physical.rs
rename to src/vfs/physical.rs
diff --git a/static/css/main.css b/static/css/main.css
index 79a0d53..2b4b5e0 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -147,7 +147,7 @@ html {
}
body {
- font-size: 1.4rem;
+ font-size: 1.6rem;
}
pre,
@@ -183,9 +183,10 @@ input {
"slnt" var(--recursive-slnt),
"CRSV" var(--recursive-crsv);
- font-feature-settings: var(--recursive-simplified-f),
- var(--recursive-simplified-g), var(--recursive-simplified-l),
- var(--recursive-simplified-r), var(--recursive-no-serif-L-Z);
+ font-feature-settings:
+ var(--recursive-simplified-f), var(--recursive-simplified-g),
+ var(--recursive-simplified-l), var(--recursive-simplified-r),
+ var(--recursive-no-serif-L-Z);
}
h1 {
diff --git a/template/_doc.hbs b/template/_doc.hbs
new file mode 100644
index 0000000..132c397
--- /dev/null
+++ b/template/_doc.hbs
@@ -0,0 +1,35 @@
+
+
+
+
+
+ {{> components/_head.hbs }}
+
+
+
+
+
+ {{> components/_noscript.hbs }}
+
+ {{> components/_nav.hbs }}
+ {{> components/_header.hbs }}
+
+ {{!--
+ NOTE: ~ because components/_tree.hbs must not include any extra indentation, because it may
+ contain pre elements which shouldn't be indented.
+ --}}
+ {{~> components/_tree.hbs }}
+
+ {{!-- For all pages except the one linked from the footer, include the footer icon. --}}
+ {{#if (ne page.tree_path "treehouse")}}
+ {{> components/_footer.hbs }}
+ {{/if}}
+
+
+
+
+
+
+
diff --git a/crates/treehouse/tests/it/main.rs b/tests/it/main.rs
similarity index 100%
rename from crates/treehouse/tests/it/main.rs
rename to tests/it/main.rs
diff --git a/crates/treehouse/tests/it/vfs.rs b/tests/it/vfs.rs
similarity index 100%
rename from crates/treehouse/tests/it/vfs.rs
rename to tests/it/vfs.rs
diff --git a/crates/treehouse/tests/it/vfs/cd.rs b/tests/it/vfs/cd.rs
similarity index 100%
rename from crates/treehouse/tests/it/vfs/cd.rs
rename to tests/it/vfs/cd.rs
diff --git a/crates/treehouse/tests/it/vfs/file.rs b/tests/it/vfs/file.rs
similarity index 100%
rename from crates/treehouse/tests/it/vfs/file.rs
rename to tests/it/vfs/file.rs
diff --git a/crates/treehouse/tests/it/vfs/mount_points.rs b/tests/it/vfs/mount_points.rs
similarity index 100%
rename from crates/treehouse/tests/it/vfs/mount_points.rs
rename to tests/it/vfs/mount_points.rs
diff --git a/crates/treehouse/tests/it/vfs/physical.rs b/tests/it/vfs/physical.rs
similarity index 100%
rename from crates/treehouse/tests/it/vfs/physical.rs
rename to tests/it/vfs/physical.rs
diff --git a/crates/treehouse/tests/it/vfs_physical/test.txt b/tests/it/vfs_physical/test.txt
similarity index 100%
rename from crates/treehouse/tests/it/vfs_physical/test.txt
rename to tests/it/vfs_physical/test.txt
From 550c062327815c4c49dee4c28c40873e20790051 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=83=AA=E3=82=AD=E8=90=8C?=
Date: Thu, 10 Jul 2025 16:50:41 +0200
Subject: [PATCH 2/4] factor out simple templates into a separate
SimpleTemplateDir
there's no need to bloat TreehouseDir with that logic
---
src/generate.rs | 147 +++-----------------------------
src/generate/atom.rs | 3 +-
src/generate/simple_template.rs | 78 ++++++++++++-----
src/generate/tree.rs | 115 ++++++++++++++++++++++++-
src/vfs.rs | 6 ++
src/vfs/html_canonicalize.rs | 1 +
src/vfs/overlay.rs | 17 ++++
7 files changed, 211 insertions(+), 156 deletions(-)
diff --git a/src/generate.rs b/src/generate.rs
index ec43d98..7ea0bce 100644
--- a/src/generate.rs
+++ b/src/generate.rs
@@ -4,7 +4,7 @@ mod include_static_helper;
mod simple_template;
mod tree;
-use std::{collections::HashMap, fmt, ops::ControlFlow, sync::Arc};
+use std::{ops::ControlFlow, sync::Arc};
use atom::FeedDir;
use dir_helper::DirHelper;
@@ -17,10 +17,14 @@ use crate::{
config::Config,
dirs::Dirs,
fun::seasons::Season,
+ generate::{
+ simple_template::SimpleTemplateDir,
+ tree::{DirIndex, TreehouseDir},
+ },
sources::Sources,
vfs::{
- self, AnchoredAtExt, Cd, Content, ContentCache, Dir, DynDir, Entries, HtmlCanonicalize,
- MemDir, Overlay, ToDynDir, VPath, VPathBuf,
+ self, layered_dir, AnchoredAtExt, Cd, Content, ContentCache, Dir, DynDir, Entries,
+ HtmlCanonicalize, MemDir, Overlay, ToDynDir, VPath, VPathBuf,
},
};
@@ -76,134 +80,6 @@ fn load_templates(handlebars: &mut Handlebars, dir: &dyn Dir) {
});
}
-struct TreehouseDir {
- dirs: Arc,
- sources: Arc,
- handlebars: Arc>,
- dir_index: DirIndex,
-}
-
-impl TreehouseDir {
- fn new(
- dirs: Arc,
- sources: Arc,
- handlebars: Arc>,
- dir_index: DirIndex,
- ) -> Self {
- Self {
- dirs,
- sources,
- handlebars,
- dir_index,
- }
- }
-
- #[instrument("TreehouseDir::dir", skip(self))]
- fn dir(&self, path: &VPath) -> Vec {
- // NOTE: This does not include simple templates, because that's not really needed right now.
-
- let mut index = &self.dir_index;
- for component in path.segments() {
- if let Some(child) = index.children.get(component) {
- index = child;
- } else {
- // There cannot possibly be any entries under an invalid path.
- // Bail early.
- return vec![];
- }
- }
-
- index
- .children
- .values()
- .map(|child| child.full_path.clone())
- .collect()
- }
-
- #[instrument("TreehouseDir::content", skip(self))]
- fn content(&self, path: &VPath) -> Option {
- let path = if path.is_root() {
- VPath::new_const("index")
- } else {
- path
- };
-
- self.sources
- .treehouse
- .files_by_tree_path
- .get(path)
- .map(|&file_id| {
- Content::new(
- "text/html",
- tree::generate_or_error(&self.sources, &self.dirs, &self.handlebars, file_id)
- .into(),
- )
- })
- .or_else(|| {
- if path.file_name().is_some_and(|s| !s.starts_with('_')) {
- let template_name = path.with_extension("hbs");
- if self.handlebars.has_template(template_name.as_str()) {
- return Some(Content::new(
- "text/html",
- simple_template::generate_or_error(
- &self.sources,
- &self.handlebars,
- template_name.as_str(),
- )
- .into(),
- ));
- }
- }
- None
- })
- }
-}
-
-impl Dir for TreehouseDir {
- fn query(&self, path: &VPath, query: &mut vfs::Query) {
- query.provide(|| Entries(self.dir(path)));
- query.try_provide(|| self.content(path));
- }
-}
-
-impl fmt::Debug for TreehouseDir {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("TreehouseDir")
- }
-}
-
-/// Acceleration structure for `dir` operations on [`TreehouseDir`]s.
-#[derive(Debug, Default)]
-struct DirIndex {
- full_path: VPathBuf,
- children: HashMap,
-}
-
-impl DirIndex {
- #[instrument(name = "DirIndex::new", skip(paths))]
- pub fn new<'a>(paths: impl Iterator- ) -> Self {
- let mut root = DirIndex::default();
-
- for path in paths {
- let mut parent = &mut root;
- let mut full_path = VPath::ROOT.to_owned();
- for segment in path.segments() {
- full_path.push(segment);
- let child = parent
- .children
- .entry(segment.to_owned())
- .or_insert_with(|| DirIndex {
- full_path: full_path.clone(),
- children: HashMap::new(),
- });
- parent = child;
- }
- }
-
- root
- }
-}
-
pub fn target(dirs: Arc, sources: Arc) -> DynDir {
let mut handlebars = create_handlebars(&sources.config.site, dirs.static_.clone());
load_templates(&mut handlebars, &dirs.template);
@@ -226,13 +102,16 @@ pub fn target(dirs: Arc, sources: Arc) -> DynDir {
);
let dir_index = DirIndex::new(sources.treehouse.files_by_tree_path.keys().map(|x| &**x));
- let tree_view = TreehouseDir::new(dirs, sources, handlebars, dir_index);
+ let treehouse_dir = layered_dir(&[
+ TreehouseDir::new(dirs, sources.clone(), handlebars.clone(), dir_index).to_dyn(),
+ SimpleTemplateDir::new(sources.clone(), handlebars.clone()).to_dyn(),
+ ]);
- let tree_view = ContentCache::new(tree_view);
+ let tree_view = ContentCache::new(treehouse_dir);
tree_view.warm_up();
let tree_view = HtmlCanonicalize::new(tree_view);
- Overlay::new(tree_view.to_dyn(), root.to_dyn())
+ layered_dir(&[tree_view.to_dyn(), root.to_dyn()])
.anchored_at(VPath::ROOT.to_owned())
.to_dyn()
}
diff --git a/src/generate/atom.rs b/src/generate/atom.rs
index 9a39f7c..f41bb9b 100644
--- a/src/generate/atom.rs
+++ b/src/generate/atom.rs
@@ -4,8 +4,7 @@ use anyhow::Context;
use chrono::{DateTime, Utc};
use handlebars::Handlebars;
use serde::Serialize;
-use tracing::{info, info_span, instrument};
-use ulid::Ulid;
+use tracing::{info_span, instrument};
use crate::{
dirs::Dirs,
diff --git a/src/generate/simple_template.rs b/src/generate/simple_template.rs
index 6ed88e6..879485b 100644
--- a/src/generate/simple_template.rs
+++ b/src/generate/simple_template.rs
@@ -1,30 +1,70 @@
+use std::{fmt, sync::Arc};
+
use anyhow::Context;
use handlebars::Handlebars;
use tracing::instrument;
-use crate::sources::Sources;
+use crate::{
+ sources::Sources,
+ vfs::{Content, Dir, Query, VPath},
+};
use super::BaseTemplateData;
-#[instrument(name = "simple_template::generate", skip(sources, handlebars))]
-pub fn generate(
- sources: &Sources,
- handlebars: &Handlebars,
- template_name: &str,
-) -> anyhow::Result {
- let base_template_data = BaseTemplateData::new(sources);
- handlebars
- .render(template_name, &base_template_data)
- .context("failed to render template")
+pub struct SimpleTemplateDir {
+ sources: Arc,
+ handlebars: Arc>,
}
-pub fn generate_or_error(
- sources: &Sources,
- handlebars: &Handlebars,
- template_name: &str,
-) -> String {
- match generate(sources, handlebars, template_name) {
- Ok(html) => html,
- Err(error) => format!("error: {error:?}"),
+impl SimpleTemplateDir {
+ pub fn new(sources: Arc, handlebars: Arc>) -> Self {
+ Self {
+ sources,
+ handlebars,
+ }
+ }
+
+ #[instrument(name = "simple_template::generate", skip(self))]
+ fn generate(&self, template_name: &str) -> anyhow::Result {
+ let base_template_data = BaseTemplateData::new(&self.sources);
+ self.handlebars
+ .render(template_name, &base_template_data)
+ .context("failed to render template")
+ }
+
+ fn generate_or_error(&self, template_name: &str) -> String {
+ match self.generate(template_name) {
+ Ok(html) => html,
+ Err(error) => format!("error: {error:?}"),
+ }
+ }
+
+ #[instrument("TreehouseDir::content", skip(self))]
+ fn content(&self, path: &VPath) -> Option {
+ if path.file_name().is_some_and(|s| !s.starts_with('_')) {
+ let template_name = path.with_extension("hbs");
+ if self.handlebars.has_template(template_name.as_str()) {
+ return Some(Content::new(
+ "text/html",
+ self.generate_or_error(template_name.as_str()).into(),
+ ));
+ }
+ }
+
+ None
+ }
+}
+
+impl Dir for SimpleTemplateDir {
+ fn query(&self, path: &VPath, query: &mut Query) {
+ // NOTE: An implementation of Entries is not currently provided, because SimpleTemplateDir
+ // isn't used enough to need one.
+ query.try_provide(|| self.content(path));
+ }
+}
+
+impl fmt::Debug for SimpleTemplateDir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("SimpleTemplateDir")
}
}
diff --git a/src/generate/tree.rs b/src/generate/tree.rs
index 9fc77aa..9ecd14c 100644
--- a/src/generate/tree.rs
+++ b/src/generate/tree.rs
@@ -1,3 +1,5 @@
+use std::{collections::HashMap, fmt, sync::Arc};
+
use anyhow::{ensure, Context};
use handlebars::Handlebars;
use serde::Serialize;
@@ -5,10 +7,11 @@ use tracing::{info_span, instrument};
use crate::{
dirs::Dirs,
- generate::BaseTemplateData,
+ generate::{simple_template, BaseTemplateData},
html::{breadcrumbs::breadcrumbs_to_html, tree},
sources::Sources,
state::FileId,
+ vfs::{self, Content, Dir, Entries, VPath, VPathBuf},
};
#[derive(Serialize)]
@@ -109,3 +112,113 @@ pub fn generate_or_error(
Err(error) => format!("error: {error:?}"),
}
}
+
+pub struct TreehouseDir {
+ dirs: Arc,
+ sources: Arc,
+ handlebars: Arc>,
+ dir_index: DirIndex,
+}
+
+impl TreehouseDir {
+ pub fn new(
+ dirs: Arc,
+ sources: Arc,
+ handlebars: Arc>,
+ dir_index: DirIndex,
+ ) -> Self {
+ Self {
+ dirs,
+ sources,
+ handlebars,
+ dir_index,
+ }
+ }
+
+ #[instrument("TreehouseDir::dir", skip(self))]
+ fn dir(&self, path: &VPath) -> Vec {
+ // NOTE: This does not include simple templates, because that's not really needed right now.
+
+ let mut index = &self.dir_index;
+ for component in path.segments() {
+ if let Some(child) = index.children.get(component) {
+ index = child;
+ } else {
+ // There cannot possibly be any entries under an invalid path.
+ // Bail early.
+ return vec![];
+ }
+ }
+
+ index
+ .children
+ .values()
+ .map(|child| child.full_path.clone())
+ .collect()
+ }
+
+ #[instrument("TreehouseDir::content", skip(self))]
+ fn content(&self, path: &VPath) -> Option {
+ let path = if path.is_root() {
+ VPath::new_const("index")
+ } else {
+ path
+ };
+
+ self.sources
+ .treehouse
+ .files_by_tree_path
+ .get(path)
+ .map(|&file_id| {
+ Content::new(
+ "text/html",
+ generate_or_error(&self.sources, &self.dirs, &self.handlebars, file_id).into(),
+ )
+ })
+ }
+}
+
+impl Dir for TreehouseDir {
+ fn query(&self, path: &VPath, query: &mut vfs::Query) {
+ query.provide(|| Entries(self.dir(path)));
+ query.try_provide(|| self.content(path));
+ }
+}
+
+impl fmt::Debug for TreehouseDir {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("TreehouseDir")
+ }
+}
+
+/// Acceleration structure for `dir` operations on [`TreehouseDir`]s.
+#[derive(Debug, Default)]
+pub struct DirIndex {
+ full_path: VPathBuf,
+ children: HashMap,
+}
+
+impl DirIndex {
+ #[instrument(name = "DirIndex::new", skip(paths))]
+ pub fn new<'a>(paths: impl Iterator
- ) -> Self {
+ let mut root = DirIndex::default();
+
+ for path in paths {
+ let mut parent = &mut root;
+ let mut full_path = VPath::ROOT.to_owned();
+ for segment in path.segments() {
+ full_path.push(segment);
+ let child = parent
+ .children
+ .entry(segment.to_owned())
+ .or_insert_with(|| DirIndex {
+ full_path: full_path.clone(),
+ children: HashMap::new(),
+ });
+ parent = child;
+ }
+ }
+
+ root
+ }
+}
diff --git a/src/vfs.rs b/src/vfs.rs
index 7d9c6b4..772592e 100644
--- a/src/vfs.rs
+++ b/src/vfs.rs
@@ -168,6 +168,12 @@ impl<'a> dyn Erased<'a> + 'a {
}
}
+impl Dir for () {
+ fn query(&self, _path: &VPath, _query: &mut Query) {
+ // Noop implementation.
+ }
+}
+
impl Dir for &T
where
T: Dir,
diff --git a/src/vfs/html_canonicalize.rs b/src/vfs/html_canonicalize.rs
index fb3ee54..bd3e772 100644
--- a/src/vfs/html_canonicalize.rs
+++ b/src/vfs/html_canonicalize.rs
@@ -2,6 +2,7 @@ use core::fmt;
use super::{Dir, Query, VPath};
+/// This Dir exists to serve as a compatibility layer for very old links that end with .html.
pub struct HtmlCanonicalize {
inner: T,
}
diff --git a/src/vfs/overlay.rs b/src/vfs/overlay.rs
index 13907ed..470a076 100644
--- a/src/vfs/overlay.rs
+++ b/src/vfs/overlay.rs
@@ -2,6 +2,8 @@ use std::fmt;
use tracing::instrument;
+use crate::vfs::ToDynDir;
+
use super::{entries, Dir, DynDir, Entries, Query, VPath, VPathBuf};
pub struct Overlay {
@@ -38,3 +40,18 @@ impl fmt::Debug for Overlay {
write!(f, "Overlay({:?}, {:?})", self.base, self.overlay)
}
}
+
+pub fn layered_dir(layers: &[DynDir]) -> DynDir {
+ match layers {
+ [] => ().to_dyn(),
+ [dir] => dir.clone(),
+ [left, right] => Overlay::new(left.clone(), right.clone()).to_dyn(),
+ [left, right, rest @ ..] => {
+ let mut overlay = Overlay::new(left.clone(), right.clone());
+ for dir in rest {
+ overlay = Overlay::new(overlay.to_dyn(), dir.clone());
+ }
+ overlay.to_dyn()
+ }
+ }
+}
From 36705e7c1e7b858feb2a5d6581b222edac087d7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=83=AA=E3=82=AD=E8=90=8C?=
Date: Thu, 10 Jul 2025 16:50:41 +0200
Subject: [PATCH 3/4] adding document mode
I've been thinking a lot about the treehouse and I feel like it's time to say goodbye to the tree format.
---
Justfile | 2 +-
content/{about.tree => about/v2.tree} | 0
content/index.dj | 37 +++
content/index.tree | 4 -
src/config.rs | 2 +
src/generate.rs | 17 +-
src/generate/atom.rs | 92 +------
src/generate/doc.rs | 242 +++++++++++++++++
src/html/djot.rs | 50 +---
src/sources.rs | 24 +-
src/state.rs | 4 +-
src/tree.rs | 1 +
src/tree/attributes.rs | 6 +-
src/tree/feed.rs | 94 +++++++
static/character/riki/sitting.png | Bin 0 -> 62407 bytes
static/css/base.css | 14 +-
static/css/doc.css | 84 ++++++
static/css/main.css | 372 +++++++++++++++++++-------
static/css/page/index.css | 95 -------
static/css/tree.css | 19 +-
template/_doc.hbs | 34 ++-
template/_tree.hbs | 33 ++-
template/components/_doc.hbs | 17 ++
template/components/_feed.hbs | 20 ++
template/components/_footer.hbs | 3 +
template/components/_head.hbs | 19 +-
template/components/_jar.hbs | 16 ++
template/components/_nav.hbs | 5 -
template/components/_sidebar.hbs | 17 ++
template/components/_tree.hbs | 23 +-
treehouse.toml | 3 +-
31 files changed, 940 insertions(+), 409 deletions(-)
rename content/{about.tree => about/v2.tree} (100%)
create mode 100644 content/index.dj
create mode 100644 src/generate/doc.rs
create mode 100644 src/tree/feed.rs
create mode 100644 static/character/riki/sitting.png
create mode 100644 static/css/doc.css
create mode 100644 template/components/_doc.hbs
create mode 100644 template/components/_feed.hbs
create mode 100644 template/components/_jar.hbs
delete mode 100644 template/components/_nav.hbs
create mode 100644 template/components/_sidebar.hbs
diff --git a/Justfile b/Justfile
index 7cc2557..e9915ae 100644
--- a/Justfile
+++ b/Justfile
@@ -1,7 +1,7 @@
port := "8080"
serve:
- cargo watch -- cargo run -- serve --port {{port}}
+ RUST_BACKTRACE=1 cargo watch -- cargo run -- serve --port {{port}}
fix:
cargo run -- fix-all --apply
diff --git a/content/about.tree b/content/about/v2.tree
similarity index 100%
rename from content/about.tree
rename to content/about/v2.tree
diff --git a/content/index.dj b/content/index.dj
new file mode 100644
index 0000000..2fdb873
--- /dev/null
+++ b/content/index.dj
@@ -0,0 +1,37 @@
+title = "riki's house"
+include_feed = { name = "new", title = "Blog" }
+
++++
+
+My name's *riki moe*, or *リキ萌*!
+
+I'm a _he/him_-type cat [furry][page:philosophy/furry] doing various things with computers.
+
+I work on game optimization tools at [[CD PROJEKT RED](https://cdprojektred.com) :rarog:]{.nowrap} but that's just the tip of the iceberg!
+After hours, I program [websites](/), [compilers][def:stitchkit/repo], [audio][def:dawd3/repo], and other fun things.
+
+Such as [*video games.*][page:games]
+Like, I probably wouldn't be in the industry if I didn't like them.\
+My personal favourites are [:nap: [DELTARUNE](https://deltarune.com)]{.nowrap}, [:bean: [Animal Well](https://www.animalwell.net/)]{.nowrap}, [:fox: [TUNIC](https://tunicgame.com/)]{.nowrap}, [:hueh: [A Hat in Time](https://hatintime.com)]{.nowrap}, and [:propane: [Noita](https://noitagame.com/)]{.nowrap}.
+But also many many more, because I'm really indecisive.
+
+Or [*music.*][page:music]
+I [listen to a lot of it.][def:social/bandcamp]
+And I mean, [_a lot_.][def:social/listenbrainz]
+A metric fuck tonne.\
+I'm a huge fan of electronic genres, but also jazz and (alternative) rock from time to time.\
+I listen to [_Songs About My Cats_](https://venetiansnares.bandcamp.com/album/songs-about-my-cats) while coding.\
+My favourite artists are [C418](https://c418.bandcamp.com/album/excursions), [The Flashbulb](https://theflashbulb.bandcamp.com/album/kirlian-selections), [Aphex Twin](https://aphextwin.bandcamp.com/album/drukqs), [Squarepusher](https://squarepusher.bandcamp.com/album/ultravisitor), and [False Noise](https://upscalehq.bandcamp.com/album/floral-strobe).
+
+I kinda also [make music sometimes](https://daknus.bandcamp.com) when I feel like it.
+
+I also drew a bit of dawing (...do a bit of drawing), as evidenced by the floofee on this page.
+
+If all that sounds like an interesting bunch of words...
+
+- feel free to email me: `hi` at this domain!!
+- or add me on Discord---the nickname's *rikimoe*.
+
+I like to think I'm pretty amicable in person but I'm uh, also really socially awkward...!\
+~Please excuse any social awkwardness that may ensue from you contacting me.\
+Or me contacting you.~
diff --git a/content/index.tree b/content/index.tree
index 7f437f2..5e7245f 100644
--- a/content/index.tree
+++ b/content/index.tree
@@ -73,10 +73,6 @@ visibility = "Private"
- I'd like to make some new friends!
if you wanna meet me, email `hi` at this domain.
-% id = "about"
- content.link = "about"
-+ ## [``{=html}][page:kuroneko]{.secret}me
-
% id = "programming"
content.link = "programming"
+ ## ``{=html}programming
diff --git a/src/config.rs b/src/config.rs
index 48fe361..c55cba2 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -152,6 +152,8 @@ impl Config {
}
pub fn page_url(&self, page: &str) -> String {
+ // We don't want .dj appearing in URLs, though it exists as a disambiguator in [page:] links.
+ let page = page.strip_suffix(".dj").unwrap_or(page);
format!("{}/{}", self.site, page)
}
diff --git a/src/generate.rs b/src/generate.rs
index 7ea0bce..3caa73e 100644
--- a/src/generate.rs
+++ b/src/generate.rs
@@ -1,5 +1,6 @@
mod atom;
mod dir_helper;
+mod doc;
mod include_static_helper;
mod simple_template;
mod tree;
@@ -7,6 +8,7 @@ mod tree;
use std::{ops::ControlFlow, sync::Arc};
use atom::FeedDir;
+use chrono::{DateTime, Utc};
use dir_helper::DirHelper;
use handlebars::{handlebars_helper, Handlebars};
use include_static_helper::IncludeStaticHelper;
@@ -18,13 +20,14 @@ use crate::{
dirs::Dirs,
fun::seasons::Season,
generate::{
+ doc::DocDir,
simple_template::SimpleTemplateDir,
tree::{DirIndex, TreehouseDir},
},
sources::Sources,
vfs::{
- self, layered_dir, AnchoredAtExt, Cd, Content, ContentCache, Dir, DynDir, Entries,
- HtmlCanonicalize, MemDir, Overlay, ToDynDir, VPath, VPathBuf,
+ self, layered_dir, AnchoredAtExt, Cd, Content, ContentCache, Dir, DynDir, HtmlCanonicalize,
+ MemDir, ToDynDir, VPath, VPathBuf,
},
};
@@ -54,8 +57,10 @@ fn create_handlebars(site: &str, static_: DynDir) -> Handlebars<'static> {
let mut handlebars = Handlebars::new();
handlebars_helper!(cat: |a: String, b: String| a + &b);
+ handlebars_helper!(iso_date: |d: DateTime| d.format("%F").to_string());
handlebars.register_helper("cat", Box::new(cat));
+ handlebars.register_helper("iso_date", Box::new(iso_date));
handlebars.register_helper("asset", Box::new(DirHelper::new(site, static_.clone())));
handlebars.register_helper(
"include_static",
@@ -103,7 +108,13 @@ pub fn target(dirs: Arc, sources: Arc) -> DynDir {
let dir_index = DirIndex::new(sources.treehouse.files_by_tree_path.keys().map(|x| &**x));
let treehouse_dir = layered_dir(&[
- TreehouseDir::new(dirs, sources.clone(), handlebars.clone(), dir_index).to_dyn(),
+ TreehouseDir::new(dirs.clone(), sources.clone(), handlebars.clone(), dir_index).to_dyn(),
+ DocDir {
+ sources: sources.clone(),
+ dirs,
+ handlebars: handlebars.clone(),
+ }
+ .to_dyn(),
SimpleTemplateDir::new(sources.clone(), handlebars.clone()).to_dyn(),
]);
diff --git a/src/generate/atom.rs b/src/generate/atom.rs
index f41bb9b..1c042eb 100644
--- a/src/generate/atom.rs
+++ b/src/generate/atom.rs
@@ -11,7 +11,7 @@ use crate::{
html::djot::{self, resolve_link},
sources::Sources,
state::FileId,
- tree::SemaBranchId,
+ tree::{feed, SemaBranchId},
vfs::{self, Content, Dir, Entries, VPath, VPathBuf},
};
@@ -155,7 +155,7 @@ fn extract_entries(sources: &Sources, dirs: &Dirs, file_id: FileId) -> Vec Vec,
- link: Option,
-}
-
-fn parse_entry(
- sources: &Sources,
- dirs: &Dirs,
- file_id: FileId,
- parser: jotdown::Parser,
-) -> ParsedEntry {
- let mut parser = parser.into_offset_iter();
- while let Some((event, span)) = parser.next() {
- if let jotdown::Event::Start(jotdown::Container::Heading { .. }, _attrs) = &event {
- let mut events = vec![(event, span)];
- for (event, span) in parser.by_ref() {
- // To my knowledge headings cannot nest, so it's okay not keeping a stack here.
- let is_heading = matches!(
- event,
- jotdown::Event::End(jotdown::Container::Heading { .. })
- );
- events.push((event, span));
- if is_heading {
- break;
- }
- }
-
- let title_events: Vec<_> = events
- .iter()
- .filter(|(event, _)| {
- !matches!(
- event,
- // A little repetitive, but I don't mind.
- // The point of this is not to include extra
");
}
- Container::Heading { level, .. } => write!(out, "", level)?,
+ Container::Heading { level, .. } => write!(out, "")?,
Container::TableCell { head: false, .. } => out.push_str(""),
Container::TableCell { head: true, .. } => out.push_str(""),
Container::Caption => out.push_str(""),
@@ -537,19 +522,8 @@ impl<'a> Writer<'a> {
Raw::Html => out.push_str(s),
Raw::Other => {}
},
- Event::FootnoteReference(_label) => {
- self.diagnostics.push(Diagnostic {
- severity: Severity::Error,
- code: Some("djot".into()),
- message: "Djot footnotes are unsupported".into(),
- labels: vec![Label {
- style: LabelStyle::Primary,
- file_id: self.renderer.file_id,
- range,
- message: "".into(),
- }],
- notes: vec![],
- });
+ Event::FootnoteReference(label) => {
+ out.push_str(label);
}
Event::Symbol(sym) => {
if let Some(vpath) = self.renderer.config.emoji.get(sym.as_ref()) {
@@ -624,7 +598,7 @@ impl<'a> Writer<'a> {
}
out.push_str("
Some("""),
_ => None,
}
- .map_or(false, |s| {
+ .is_some_and(|s| {
ent = s;
true
})
diff --git a/src/sources.rs b/src/sources.rs
index 56feac4..9e0938a 100644
--- a/src/sources.rs
+++ b/src/sources.rs
@@ -2,7 +2,7 @@ use std::{collections::HashMap, ops::ControlFlow};
use anyhow::{anyhow, Context};
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
-use tracing::{info_span, instrument};
+use tracing::{error, info_span, instrument};
use crate::{
config::Config,
@@ -66,14 +66,19 @@ fn load_trees(config: &Config, dirs: &Dirs) -> anyhow::Result {
let mut parsed_trees = HashMap::new();
let mut paths = vec![];
+ let mut doc_paths = vec![];
vfs::walk_dir_rec(&*dirs.content, VPath::ROOT, &mut |path| {
- if path.extension() == Some("tree") {
- paths.push(path.to_owned());
+ match path.extension() {
+ Some("tree") => paths.push(path.to_owned()),
+ Some("dj") => doc_paths.push(path.to_owned()),
+ _ => (),
}
ControlFlow::Continue(())
});
+ // Trees
+
// NOTE: Sources are filled in later; they can be left out until a call to report_diagnostics.
let file_ids: Vec<_> = paths
.iter()
@@ -132,5 +137,18 @@ fn load_trees(config: &Config, dirs: &Dirs) -> anyhow::Result {
report_diagnostics(&treehouse, &diagnostics)?;
+ // Docs
+
+ for path in doc_paths {
+ if let Some(input) =
+ vfs::query::(&dirs.content, &path).and_then(|c| c.string().ok())
+ {
+ let file_id = treehouse.add_file(path.clone(), Source::Other(input));
+ treehouse.files_by_doc_path.insert(path, file_id);
+ } else {
+ error!("doc {path} does not exist in content directory even though it was enumerated via walk_dir_rec");
+ }
+ }
+
Ok(treehouse)
}
diff --git a/src/state.rs b/src/state.rs
index 9a592b9..ab98670 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -66,7 +66,8 @@ pub struct FileId(usize);
/// Treehouse compilation context.
pub struct Treehouse {
pub files: Vec,
- pub files_by_tree_path: HashMap,
+ pub files_by_tree_path: HashMap, // trees only
+ pub files_by_doc_path: HashMap, // docs only
pub feeds_by_name: HashMap,
pub tree: SemaTree,
@@ -83,6 +84,7 @@ impl Treehouse {
Self {
files: vec![],
files_by_tree_path: HashMap::new(),
+ files_by_doc_path: HashMap::new(),
feeds_by_name: HashMap::new(),
tree: SemaTree::default(),
diff --git a/src/tree.rs b/src/tree.rs
index b922e32..c5a62e1 100644
--- a/src/tree.rs
+++ b/src/tree.rs
@@ -1,5 +1,6 @@
pub mod ast;
pub mod attributes;
+pub mod feed;
pub mod mini_template;
pub mod pull;
diff --git a/src/tree/attributes.rs b/src/tree/attributes.rs
index 60fed8b..c18fa3e 100644
--- a/src/tree/attributes.rs
+++ b/src/tree/attributes.rs
@@ -23,10 +23,6 @@ pub struct RootAttributes {
#[serde(default = "default_icon")]
pub icon: String,
- /// Summary of the generated .html page.
- #[serde(default)]
- pub description: Option,
-
/// ID of picture attached to the page, to be used as a thumbnail.
#[serde(default)]
pub thumbnail: Option,
@@ -50,7 +46,7 @@ pub struct RootAttributes {
#[serde(default)]
pub timestamps: Option,
- /// When specified, this page will have a corresponding Atom feed under `rss/{feed}.xml`.
+ /// When specified, this page will have a corresponding Atom feed under `feed/{feed}.atom`.
///
/// In feeds, top-level branches are expected to have a single heading containing the post title.
/// Their children are turned into the post description
diff --git a/src/tree/feed.rs b/src/tree/feed.rs
new file mode 100644
index 0000000..b8c0d77
--- /dev/null
+++ b/src/tree/feed.rs
@@ -0,0 +1,94 @@
+use crate::{
+ dirs::Dirs,
+ html::djot::{self, resolve_link},
+ sources::Sources,
+ state::FileId,
+};
+
+#[derive(Debug, Clone)]
+pub struct ParsedEntry {
+ pub title: Option,
+ pub link: Option,
+}
+
+pub fn parse_entry(
+ sources: &Sources,
+ dirs: &Dirs,
+ file_id: FileId,
+ parser: jotdown::Parser,
+) -> ParsedEntry {
+ let mut parser = parser.into_offset_iter();
+ while let Some((event, span)) = parser.next() {
+ if let jotdown::Event::Start(jotdown::Container::Heading { .. }, _attrs) = &event {
+ let mut events = vec![(event, span)];
+ for (event, span) in parser.by_ref() {
+ // To my knowledge headings cannot nest, so it's okay not keeping a stack here.
+ let is_heading = matches!(
+ event,
+ jotdown::Event::End(jotdown::Container::Heading { .. })
+ );
+ events.push((event, span));
+ if is_heading {
+ break;
+ }
+ }
+
+ let title_events: Vec<_> = events
+ .iter()
+ .filter(|(event, _)| {
+ !matches!(
+ event,
+ // A little repetitive, but I don't mind.
+ // The point of this is not to include extra