Browse Source

first commit

main
cynthia 2 years ago
commit
05821b77a4
  1. 1
      .gitignore
  2. 7
      Cargo.lock
  3. 8
      Cargo.toml
  4. 150
      src/main.rs

1
.gitignore

@ -0,0 +1 @@
/target

7
Cargo.lock

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "details"
version = "0.1.0"

8
Cargo.toml

@ -0,0 +1,8 @@
[package]
name = "details"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

150
src/main.rs

@ -0,0 +1,150 @@
#![allow(dead_code)]
use std::collections::BTreeMap;
use std::io::{Error as IoError, Write};
use std::{env::args, fs};
fn main() {
let filename = args().nth(1).expect("no file given");
let detail = Detail::new(&filename).unwrap();
let out = filename
.strip_suffix(".detail")
.unwrap_or(&filename)
.to_string()
+ ".html";
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())
.unwrap_or_else(|_| panic!("unable to write to {}", out));
}
// ~~~ data structures ~~~
struct Detail {
passages: BTreeMap<String, String>,
node_graph: Vec<Vec<bool>>,
}
impl Detail {
fn new(filename: &str) -> Result<Self, DetailError> {
let contents = fs::read_to_string(filename).map_err(|err| DetailError::Io(err))?;
let mut passages = BTreeMap::new();
let mut cur_passage: Option<String> = None;
let mut cur_lines = String::new();
for line in contents.lines() {
let line = line.trim();
// if line begins with ~detail
if let Some(passage_name) = line.strip_prefix("~detail ") {
// 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();
if !cur_lines.is_empty() {
if passages.contains_key(&prev_passage) {
println!("WARNING: passage name \"{}\" duplicated", prev_passage);
passages.remove(&prev_passage);
} else {
// clear cur_lines and insert
passages.insert(prev_passage, std::mem::take(&mut cur_lines));
}
}
}
cur_passage = Some(passage_name.to_string());
} else {
// case: regular line
cur_lines += line;
}
}
// add last passage
if let Some(prev_passage) = cur_passage {
let prev_passage = prev_passage.to_string();
if !cur_lines.is_empty() {
if passages.contains_key(&prev_passage) {
println!("WARNING: passage name \"{}\" duplicated", prev_passage);
passages.remove(&prev_passage);
} else {
// clear cur_lines and insert
passages.insert(prev_passage, std::mem::take(&mut cur_lines));
}
}
}
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 {
passages,
node_graph,
};
detail.build_graph();
if detail.check_valid() {
Ok(detail)
} else {
Err(DetailError::InfiniteLoop)
}
}
fn into_html(self) -> Option<String> {
self.flatten(&"start")
}
fn flatten(&self, rule: &str) -> Option<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 (display, detail_to) = piece.split_once('~').unwrap_or((piece, piece));
let expand = self.flatten(&detail_to)?;
output += "<details><summary>";
output += display;
output += "</summary>";
output += &expand;
output += "</details>";
}
}
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;
}
}
}
}
}
// TODO actually write this
fn check_valid(&self) -> bool {
true
}
}
#[derive(Debug)]
enum DetailError {
Io(IoError),
InfiniteLoop,
}
Loading…
Cancel
Save