add config

This commit is contained in:
liquidex 2023-08-27 15:59:52 +02:00
parent 2c2d529056
commit 00947ec966
8 changed files with 91 additions and 41 deletions

View file

@ -105,7 +105,7 @@
- but without overwhelming your computer or bandwidth - but without overwhelming your computer or bandwidth
% id = "01H89RFHCQ1XA3BB3BTKXH36CX" % id = "01H89RFHCQ1XA3BB3BTKXH36CX"
- you can disable the JavaScript, and everything will still work - you can disable the JavaScript, and everything will mostly work
% id = "01H89RFHCQS2WW7PBP1YV0BEJZ" % id = "01H89RFHCQS2WW7PBP1YV0BEJZ"
- but you may not find the experience favorable - but you may not find the experience favorable
@ -123,7 +123,9 @@
+ can you even call it that? + can you even call it that?
% id = "01H89RFHCQ48R7BCZV8JWPVFCY" % id = "01H89RFHCQ48R7BCZV8JWPVFCY"
- have I invented something new here? + have I invented something new here?
- the "Choose Your Own Poem" lol
% id = "01H89RFHCQAXJ0ST31TP1A104V" % id = "01H89RFHCQAXJ0ST31TP1A104V"
+ ### the treehouse is a mostly statically generated website + ### the treehouse is a mostly statically generated website

View file

@ -20,6 +20,7 @@ use walkdir::WalkDir;
use crate::{ use crate::{
cli::parse::parse_tree_with_diagnostics, cli::parse::parse_tree_with_diagnostics,
config::Config,
html::{navmap::build_navigation_map, tree::branches_to_html}, html::{navmap::build_navigation_map, tree::branches_to_html},
tree::SemaRoots, tree::SemaRoots,
}; };
@ -95,7 +96,7 @@ impl Generator {
Ok(()) Ok(())
} }
fn generate_all_files(&self, dirs: &Dirs<'_>) -> anyhow::Result<Treehouse> { fn generate_all_files(&self, config: &Config, paths: &Paths<'_>) -> anyhow::Result<Treehouse> {
let mut treehouse = Treehouse::new(); let mut treehouse = Treehouse::new();
let mut handlebars = Handlebars::new(); let mut handlebars = Handlebars::new();
@ -103,7 +104,7 @@ impl Generator {
&mut handlebars, &mut handlebars,
&mut treehouse, &mut treehouse,
"tree", "tree",
&dirs.template_dir.join("tree.hbs"), &paths.template_dir.join("tree.hbs"),
)?; )?;
struct ParsedTree { struct ParsedTree {
@ -116,11 +117,11 @@ impl Generator {
for path in &self.tree_files { for path in &self.tree_files {
let utf8_filename = path.to_string_lossy(); let utf8_filename = path.to_string_lossy();
let tree_path = path.strip_prefix(dirs.content_dir).unwrap_or(path); let tree_path = path.strip_prefix(paths.content_dir).unwrap_or(path);
let target_path = if tree_path == OsStr::new("index.tree") { let target_path = if tree_path == OsStr::new("index.tree") {
dirs.target_dir.join("index.html") paths.target_dir.join("index.html")
} else { } else {
dirs.target_dir.join(tree_path).with_extension("html") paths.target_dir.join(tree_path).with_extension("html")
}; };
debug!("generating: {path:?} -> {target_path:?}"); debug!("generating: {path:?} -> {target_path:?}");
@ -162,12 +163,19 @@ impl Generator {
branches_to_html( branches_to_html(
&mut tree, &mut tree,
&mut treehouse, &mut treehouse,
config,
parsed_tree.file_id, parsed_tree.file_id,
&roots.branches, &roots.branches,
); );
treehouse.roots.insert(parsed_tree.tree_path, roots); treehouse.roots.insert(parsed_tree.tree_path, roots);
let template_data = TemplateData { tree }; #[derive(Serialize)]
pub struct TemplateData<'a> {
pub config: &'a Config,
pub tree: String,
}
let template_data = TemplateData { config, tree };
let templated_html = match handlebars.render("tree", &template_data) { let templated_html = match handlebars.render("tree", &template_data) {
Ok(html) => html, Ok(html) => html,
Err(error) => { Err(error) => {
@ -196,37 +204,38 @@ impl Generator {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Dirs<'a> { pub struct Paths<'a> {
pub target_dir: &'a Path, pub target_dir: &'a Path,
pub static_dir: &'a Path, pub static_dir: &'a Path,
pub template_dir: &'a Path, pub template_dir: &'a Path,
pub content_dir: &'a Path, pub content_dir: &'a Path,
pub config_file: &'a Path,
} }
#[derive(Serialize)] pub fn regenerate(paths: &Paths<'_>) -> anyhow::Result<()> {
pub struct TemplateData {
pub tree: String,
}
pub fn regenerate(dirs: &Dirs<'_>) -> anyhow::Result<()> {
let start = Instant::now(); let start = Instant::now();
info!("loading config");
let mut config = Config::load(paths.config_file)?;
config.site = std::env::var("TREEHOUSE_SITE").unwrap_or(config.site);
info!("cleaning target directory"); info!("cleaning target directory");
let _ = std::fs::remove_dir_all(dirs.target_dir); let _ = std::fs::remove_dir_all(paths.target_dir);
std::fs::create_dir_all(dirs.target_dir)?; std::fs::create_dir_all(paths.target_dir)?;
info!("copying static directory to target directory"); info!("copying static directory to target directory");
copy_dir(dirs.static_dir, dirs.target_dir.join("static"))?; copy_dir(paths.static_dir, paths.target_dir.join("static"))?;
info!("generating standalone pages"); info!("generating standalone pages");
let mut generator = Generator::default(); let mut generator = Generator::default();
generator.add_directory_rec(dirs.content_dir)?; generator.add_directory_rec(paths.content_dir)?;
let treehouse = generator.generate_all_files(dirs)?; let treehouse = generator.generate_all_files(&config, paths)?;
info!("generating navigation map"); info!("generating navigation map");
let navigation_map = build_navigation_map(&treehouse, "index"); let navigation_map = build_navigation_map(&treehouse, "index");
std::fs::write( std::fs::write(
dirs.target_dir.join("navmap.js"), paths.target_dir.join("navmap.js"),
navigation_map.to_javascript(), navigation_map.to_javascript(),
)?; )?;
@ -238,10 +247,10 @@ pub fn regenerate(dirs: &Dirs<'_>) -> anyhow::Result<()> {
Ok(()) Ok(())
} }
pub fn regenerate_or_report_error(dirs: &Dirs<'_>) { pub fn regenerate_or_report_error(paths: &Paths<'_>) {
info!("regenerating site content"); info!("regenerating site content");
match regenerate(dirs) { match regenerate(paths) {
Ok(_) => (), Ok(_) => (),
Err(error) => eprintln!("error: {error:?}"), Err(error) => eprintln!("error: {error:?}"),
} }

View file

@ -0,0 +1,25 @@
use std::{collections::HashMap, path::Path};
use anyhow::Context;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Config {
/// Website root; used when generating links.
/// Can also be specified using the environment variable `$TREEHOUSE_SITE`. (this is the
/// preferred way of setting this in production, so as not to clobber treehouse.toml.)
pub site: String,
/// User-defined keys.
pub user: HashMap<String, String>,
/// Links exported to Markdown for use with reference syntax `[text][key]`.
pub links: HashMap<String, String>,
}
impl Config {
pub fn load(path: &Path) -> anyhow::Result<Self> {
let string = std::fs::read_to_string(path).context("cannot read config file")?;
toml_edit::de::from_str(&string).context("error in config file")
}
}

View file

@ -4,6 +4,7 @@ use pulldown_cmark::{BrokenLink, LinkType};
use treehouse_format::pull::BranchKind; use treehouse_format::pull::BranchKind;
use crate::{ use crate::{
config::Config,
html::EscapeAttribute, html::EscapeAttribute,
state::{FileId, Treehouse}, state::{FileId, Treehouse},
tree::{attributes::Content, SemaBranchId}, tree::{attributes::Content, SemaBranchId},
@ -14,6 +15,7 @@ use super::{markdown, EscapeHtml};
pub fn branch_to_html( pub fn branch_to_html(
s: &mut String, s: &mut String,
treehouse: &mut Treehouse, treehouse: &mut Treehouse,
config: &Config,
file_id: FileId, file_id: FileId,
branch_id: SemaBranchId, branch_id: SemaBranchId,
) { ) {
@ -110,7 +112,8 @@ pub fn branch_to_html(
if let Content::Link(link) = &branch.attributes.content { if let Content::Link(link) = &branch.attributes.content {
write!( write!(
s, s,
"<noscript><a class=\"navigate icon-go\" href=\"{}.html\">Go to linked tree: <code>{}</code></a></noscript>", "<noscript><a class=\"navigate icon-go\" href=\"{}/{}.html\">Go to linked tree: <code>{}</code></a></noscript>",
EscapeAttribute(&config.site),
EscapeAttribute(link), EscapeAttribute(link),
EscapeHtml(link), EscapeHtml(link),
) )
@ -122,7 +125,8 @@ pub fn branch_to_html(
if let Content::Link(link) = &branch.attributes.content { if let Content::Link(link) = &branch.attributes.content {
write!( write!(
s, s,
"<a class=\"icon icon-go\" href=\"{}.html\" title=\"linked tree\"></a>", "<a class=\"icon icon-go\" href=\"{}/{}.html\" title=\"linked tree\"></a>",
EscapeAttribute(&config.site),
EscapeAttribute(link), EscapeAttribute(link),
) )
.unwrap(); .unwrap();
@ -144,7 +148,7 @@ pub fn branch_to_html(
let num_children = branch.children.len(); let num_children = branch.children.len();
for i in 0..num_children { for i in 0..num_children {
let child_id = treehouse.tree.branch(branch_id).children[i]; let child_id = treehouse.tree.branch(branch_id).children[i];
branch_to_html(s, treehouse, file_id, child_id); branch_to_html(s, treehouse, config, file_id, child_id);
} }
s.push_str("</ul>"); s.push_str("</ul>");
} }
@ -159,12 +163,13 @@ pub fn branch_to_html(
pub fn branches_to_html( pub fn branches_to_html(
s: &mut String, s: &mut String,
treehouse: &mut Treehouse, treehouse: &mut Treehouse,
config: &Config,
file_id: FileId, file_id: FileId,
branches: &[SemaBranchId], branches: &[SemaBranchId],
) { ) {
s.push_str("<ul>"); s.push_str("<ul>");
for &child in branches { for &child in branches {
branch_to_html(s, treehouse, file_id, child); branch_to_html(s, treehouse, config, file_id, child);
} }
s.push_str("</ul>"); s.push_str("</ul>");
} }

View file

@ -3,12 +3,13 @@ use std::path::Path;
use clap::Parser; use clap::Parser;
use cli::{ use cli::{
fix::fix_file_cli, fix::fix_file_cli,
regenerate::{self, regenerate_or_report_error, Dirs}, regenerate::{self, regenerate_or_report_error, Paths},
Command, ProgramArgs, Command, ProgramArgs,
}; };
use log::{error, info}; use log::{error, info};
mod cli; mod cli;
mod config;
mod html; mod html;
mod paths; mod paths;
mod state; mod state;
@ -19,8 +20,9 @@ async fn fallible_main() -> anyhow::Result<()> {
match args.command { match args.command {
Command::Regenerate(regenerate_args) => { Command::Regenerate(regenerate_args) => {
let dirs = Dirs { let dirs = Paths {
target_dir: Path::new("target/site"), target_dir: Path::new("target/site"),
config_file: Path::new("treehouse.toml"),
// NOTE: These are intentionally left unconfigurable from within treehouse.toml // NOTE: These are intentionally left unconfigurable from within treehouse.toml
// because this is is one of those things that should be consistent between sites. // because this is is one of those things that should be consistent between sites.

View file

@ -1,3 +1,5 @@
// This is definitely not a three.js ripoff.
import { navigationMap } from "/navmap.js"; import { navigationMap } from "/navmap.js";
const branchStateKey = "treehouse.openBranches"; const branchStateKey = "treehouse.openBranches";
@ -68,7 +70,7 @@ class LinkedBranch extends Branch {
async loadTreePromise(_initiator) { async loadTreePromise(_initiator) {
try { try {
let response = await fetch(`/${this.linkedTree}.html`); let response = await fetch(`${TREEHOUSE_SITE}/${this.linkedTree}.html`);
if (response.status == 404) { if (response.status == 404) {
throw `Hmm, seems like the tree "${this.linkedTree}" does not exist.`; throw `Hmm, seems like the tree "${this.linkedTree}" does not exist.`;
} }
@ -107,7 +109,7 @@ function expandDetailsRecursively(element) {
} }
function navigateToPage(page) { function navigateToPage(page) {
window.location.pathname = `/${page}.html` window.location.href = `${TREEHOUSE_SITE}/${page}.html`
} }
async function navigateToBranch(fragment) { async function navigateToBranch(fragment) {

View file

@ -9,18 +9,19 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ site }}/static/css/main.css"> <link rel="stylesheet" href="{{ config.site }}/static/css/main.css">
<link rel="stylesheet" href="{{ site }}/static/css/tree.css"> <link rel="stylesheet" href="{{ config.site }}/static/css/tree.css">
<link rel="stylesheet" href="{{ site }}/static/font/font.css"> <link rel="stylesheet" href="{{ config.site }}/static/font/font.css">
<script type="module" src="{{ site }}/navmap.js"></script> <script>const TREEHOUSE_SITE = `{{ config.site }}`;</script>
<script type="module" src="{{ site }}/static/js/tree.js"></script> <script type="module" src="{{ config.site }}/navmap.js"></script>
<script type="module" src="{{ site }}/static/js/usability.js"></script> <script type="module" src="{{ config.site }}/static/js/tree.js"></script>
<script type="module" src="{{ config.site }}/static/js/usability.js"></script>
</head> </head>
<body> <body>
<nav> <nav>
<a href="{{ site }}/" title="Back to homepage"> <a href="{{ config.site }}/" title="Back to homepage">
<svg class="logo" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="logo" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" <path fill-rule="evenodd" clip-rule="evenodd"
d="M8 3H7H6V4V5H4V6H6V9V10H7H10V12H11V10H12H13V9V8V7H12H11H10V8V9H7V6H8H9V5V4V3H8ZM12 9H11V8H12V9ZM7 5V4H8V5H7ZM3 5H2V6H3V5ZM10 13H11V14H10V13Z" d="M8 3H7H6V4V5H4V6H6V9V10H7H10V12H11V10H12H13V9V8V7H12H11H10V8V9H7V6H8H9V5V4V3H8ZM12 9H11V8H12V9ZM7 5V4H8V5H7ZM3 5H2V6H3V5ZM10 13H11V14H10V13Z"

View file

@ -1,5 +1,9 @@
# User settings go here. These are (string, string) key-value pairs. site = "http://localhost:8080"
# They are available under `config.user`.
[user] [user]
title = "treehouse" title = "liquidex's treehouse"
author = "liquidex" author = "liquidex"
[links]
"stitchkit/repo" = "https://github.com/liquidev/stitchkit"
"dawd3/repo" = "https://github.com/liquidev/dawd3"