Browse Source

add markdown, generate full html page

main
cynthia 8 months ago
parent
commit
254f86a3b9
  1. 58
      Cargo.lock
  2. 1
      Cargo.toml
  3. 131
      src/main.rs

58
Cargo.lock

@ -2,6 +2,64 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "details"
version = "0.1.0"
dependencies = [
"markdown",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "markdown"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef3aab6a1d529b112695f72beec5ee80e729cb45af58663ec902c8fac764ecdd"
dependencies = [
"lazy_static",
"pipeline",
"regex",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "pipeline"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d15b6607fa632996eb8a17c9041cb6071cb75ac057abd45dece578723ea8c7c0"
[[package]]
name = "regex"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"

1
Cargo.toml

@ -6,3 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
markdown = "0.3.0"

131
src/main.rs

@ -1,5 +1,4 @@
#![allow(dead_code)]
use markdown::to_html;
use std::collections::BTreeMap;
use std::io::{Error as IoError, Write};
use std::{env::args, fs};
@ -16,29 +15,56 @@ fn main() {
let mut file =
std::fs::File::create(out.clone()).unwrap_or_else(|_| panic!("couldn't create {}", out));
file.write_all(detail.into_html().unwrap().as_bytes())
let header = header();
let title = title();
let footer = footer();
let content = header + &detail.title + &title + &detail.into_html().unwrap() + &footer;
file.write_all(content.as_bytes())
.unwrap_or_else(|_| panic!("unable to write to {}", out));
}
// ~~~ data structures ~~~
struct Detail {
passages: BTreeMap<String, String>,
node_graph: Vec<Vec<bool>>,
title: String,
}
impl Detail {
fn new(filename: &str) -> Result<Self, DetailError> {
let contents = fs::read_to_string(filename).map_err(|err| DetailError::Io(err))?;
if contents.is_empty() {
return Err(DetailError::EmptyFile);
}
let mut passages = BTreeMap::new();
let mut cur_passage: Option<String> = None;
let mut cur_lines = String::new();
let mut has_title = true;
let title = contents
.lines()
.peekable()
.peek()
.unwrap()
.strip_prefix("~title")
.unwrap_or_else(|| {
has_title = false;
"details"
});
let mut lines = contents.lines();
if has_title {
lines.next();
}
for line in contents.lines() {
for line in lines {
let line = line.trim();
// if line begins with ~detail
if let Some(passage_name) = line.strip_prefix("~detail ") {
if let Some(passage_name) = line.strip_prefix("~detail") {
let passage_name = passage_name.trim();
// if this isn't the first passage, add previous passage to map
if let Some(prev_passage) = cur_passage {
let prev_passage = prev_passage.to_string();
@ -57,6 +83,7 @@ impl Detail {
} else {
// case: regular line
cur_lines += line;
cur_lines += "\n";
}
}
@ -74,24 +101,15 @@ impl Detail {
}
}
let mut node_graph = Vec::new();
node_graph.resize_with(passages.len(), || {
let mut row = Vec::new();
row.resize(passages.len(), false);
row
});
let mut detail = Self {
let detail = Self {
passages,
node_graph,
title: title.to_string(),
};
detail.build_graph();
if detail.check_valid() {
Ok(detail)
} else {
Err(DetailError::InfiniteLoop)
match detail.check_valid(&"start", &mut Vec::new()) {
Some(true) => Ok(detail),
Some(false) => Err(DetailError::InfiniteLoop),
None => Err(DetailError::FlattenError),
}
}
@ -105,7 +123,7 @@ impl Detail {
for (sep, piece) in rule.split('#').enumerate() {
// search keys
if sep % 2 == 0 {
output += piece;
output += &to_html(&piece);
} else {
let (display, detail_to) = piece.split_once('~').unwrap_or((piece, piece));
let expand = self.flatten(&detail_to)?;
@ -119,27 +137,28 @@ impl Detail {
Some(output)
}
// don't speak to me about how nested this method is.
fn build_graph(&mut self) {
for (i, content) in self.passages.values().enumerate() {
for (sep, piece) in content.split('#').enumerate() {
// search keys
if sep % 2 == 1 {
if let Some((_, detail_to)) = piece.split_once('~') {
if let Some(j) = self.passages.keys().position(|name| name == &detail_to) {
self.node_graph[i][j] = true;
}
} else if let Some(j) = self.passages.keys().position(|name| name == &piece) {
self.node_graph[i][j] = true;
}
fn check_valid(&self, rule: &str, already_visited: &mut Vec<String>) -> Option<bool> {
already_visited.push(rule.to_string());
let rule = self.passages.get(rule)?;
let mut output = String::new();
for (sep, piece) in rule.split('#').enumerate() {
// search keys
if sep % 2 == 0 {
output += piece;
} else {
let (_, detail_to) = piece.split_once('~').unwrap_or((piece, piece));
if already_visited
.iter()
.find(|passage| *passage == detail_to)
.is_none()
{
return self.check_valid(&detail_to, already_visited);
} else {
return Some(false);
}
}
}
}
// TODO actually write this
fn check_valid(&self) -> bool {
true
Some(true)
}
}
@ -147,4 +166,36 @@ impl Detail {
enum DetailError {
Io(IoError),
InfiniteLoop,
FlattenError,
EmptyFile,
}
fn header() -> String {
r#"<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>"#
.to_string()
}
fn title() -> String {
r#"</title>
<style>
details {
margin-left: 1em;
}
</style>
</head>
<body>
"#
.to_string()
}
fn footer() -> String {
r#"</body>
</html>
"#
.to_string()
}
Loading…
Cancel
Save