about summary refs log tree commit diff
path: root/converge
diff options
context:
space:
mode:
Diffstat (limited to 'converge')
-rwxr-xr-x[-rw-r--r--]converge/Cargo.toml3
-rwxr-xr-xconverge/example.html185
-rwxr-xr-x[-rw-r--r--]converge/readme.md7
-rwxr-xr-x[-rw-r--r--]converge/src/main.rs39
-rwxr-xr-xconverge/src/timedb.rs97
5 files changed, 309 insertions, 22 deletions
diff --git a/converge/Cargo.toml b/converge/Cargo.toml
index 4dc9e4b..98481f6 100644..100755
--- a/converge/Cargo.toml
+++ b/converge/Cargo.toml
@@ -6,6 +6,9 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+bempline = "0.8.1"
 camino = "1.1.6"
 cutie = { path = "../", version = "0.1.0" }
 thiserror = "1.0.52"
+time = { version = "0.3.31", features = ["formatting", "macros"] }
+scurvy = { path = "../../scurvy" }
diff --git a/converge/example.html b/converge/example.html
new file mode 100755
index 0000000..970cc06
--- /dev/null
+++ b/converge/example.html
@@ -0,0 +1,185 @@
+/Users/gen/src/inf/served/touching-grass.html
+/Users/gen/src/inf/fixtures/post.html
+/Users/gen/src/inf/fixtures/base.html
+Looking for html
+Looking for head
+Looking for title
+	closed title
+	closed head
+Looking for body
+Looking for ul
+Looking for li
+Looking for a
+	closed a
+	closed li
+	closed ul
+Looking for main
+	closed main
+Looking for footer
+Looking for ul
+Looking for li
+	closed li
+Looking for li
+Looking for abbr
+	closed abbr
+	closed li
+Looking for li
+Looking for abbr
+	closed abbr
+	closed li
+	closed ul
+	closed footer
+	closed body
+	closed html
+Looking for nav
+Looking for a
+	closed a
+	closed nav
+BEFORE
+Looking for main
+	closed main
+Looking for section
+Looking for video
+	closed video
+Looking for ul
+Looking for li
+	closed li
+Looking for li
+Looking for a
+	closed a
+	closed li
+Looking for li
+Looking for a
+	closed a
+	closed li
+Looking for li
+	closed li
+Looking for li
+Looking for input
+Looking for label
+	closed label
+	closed input
+	closed li
+	closed ul
+	closed section
+Looking for script
+	parse special
+Looking for p
+	closed p
+Looking for p
+	closed p
+Looking for p
+Looking for span
+	closed span
+Looking for i
+	closed i
+Looking for span
+	closed span
+	closed p
+Looking for p
+	closed p
+<html>
+
+<head>
+	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+	<meta charset="utf-8" />
+
+	<link rel="icon" type="image/png" href="/3directions.png" />
+	<link rel="icon" type="image/svg+xml" href="/3directions.svg" />
+
+	<title></title>
+
+	<link rel="stylesheet" href="/styles/common.css" />
+</head>
+
+<body>
+	<ul id="nav-access">
+		<li><a href="#content">Skip to main content</a></li>
+	</ul>
+
+	<nav class="sized">
+	<a id="home" href="/" alt="home">&larr; home</a>
+</nav><main id="content" class="writing sized"><section style="width: 100%; text-align: right; padding: 8px 0">
+	<video id="grass" controls width="100%" poster="grass_poster.jpg" preload="metadata" loop>
+		<source src="grass_720p.mp4" type="video/mp4" />
+		<track default src="grass.vtt" />
+	</video>
+	<ul>
+		<li class="small">download</li>
+		<li><a href="grass.mp4" download>[1080p | 7.1MB]</a></li>
+		<li><a href="grass_720p.mp4" download>[720p | 1.9MB]</a></li>
+		<li id="long"></li>
+		<li><input type="checkbox" checked id="loop"><label> loop video?</label></input></li>
+	</ul>
+</section>
+
+<script>
+	document.addEventListener("DOMContentLoaded", setup);
+
+	const video = document.getElementById("grass");
+	function setup() {
+		let marks = document.getElementsByClassName("mark");
+		for (let i = 0; i < marks.length; ++i) {
+			marks[i].addEventListener('click', markClick)
+		}
+		console.log(marks);
+
+		let loop = document.getElementById('loop');
+		loop.addEventListener('change', loopChanged)
+
+		// Fire once with a fake event so we aren't desynced
+		loopChanged({ 'target': loop });
+	}
+
+	function markClick(event) {
+		let target = event.target;
+		let time = parseFloat(target.getAttribute('data-time'));
+		console.log(`seeking to ${time}`)
+		video.currentTime = time;
+	}
+
+	function loopChanged(event) {
+		let target = event.target;
+		let checked = target.checked;
+		console.log(`video looping: ${checked}`);
+		video.loop = checked;
+	}
+</script>
+
+<p>
+	I took this short video to send to a friend one day and accidentally
+	made a 106 frame masterpiece. Well, that's hyperbolic. But there's a
+	lot I enjoy about it.
+</p>
+
+<p>
+	The contrast between my orange painted nails and the surprisingly
+	green grass is pretty pleasing. I think the gentle brown of the brick
+	in the bottom-left corner helps keep from an overwhelming greenery.
+	Thanks bricks :)
+</p>
+
+<p>
+	The accidental camera movement is nice, too. I like the angle the camera is at and the way it wobbles.
+	It's clearly hand-held. At <span class="mark" data-time="1.3">1.3-ish-seconds</span>
+	you can see I gently sway forward, but seem to be less wobbly. <i>I'm braced;
+		I'm stable! I have-three-points-of-contact-with-the-ground!</i> Then, at roughly
+	<span class="mark" data-time="1.9">2&nbsp;seconds</span> when the grass finally
+	yields, I get rocked back and wobbles resume.
+</p>
+
+<p>
+	The sound! And the sound. The ripping of the grass. That planty matter finally giving way. The fibrous tearing.
+	I just like it; I enjoy it! I greatly appreciate it.
+</p></main>
+
+	<footer class="sized">
+		<ul id="dates">
+			<li id="dates-title">&nbsp;times</li>
+			<li><abbr title="creation time">c</abbr> {created}</li>
+			<li><abbr title="modification time">m</abbr> {modified}</li>
+		</ul>
+	</footer>
+</body>
+
+</html>
diff --git a/converge/readme.md b/converge/readme.md
index 5a778c3..7fcecb5 100644..100755
--- a/converge/readme.md
+++ b/converge/readme.md
@@ -6,4 +6,9 @@ Setup: <path>
 {directions}
 content
 
-{directions} content
\ No newline at end of file
+{directions} content
+
+**variables converge tries to fill**
+
+- `{file_time_created}`: time the file was created
+- `{file_time_modified}`: time the file was modified
\ No newline at end of file
diff --git a/converge/src/main.rs b/converge/src/main.rs
index 20f2683..74abe67 100644..100755
--- a/converge/src/main.rs
+++ b/converge/src/main.rs
@@ -1,32 +1,30 @@
 use std::str::FromStr;
 
 use camino::Utf8PathBuf;
+use scurvy::Argument;
 
 fn main() {
-	let mut args = std::env::args().skip(1);
-	let argc = args.len();
-	if argc == 0 {
-		eprintln!("usage: converge <content file> [supporting files ...]");
-		return;
+	let arguments = [
+		Argument::arg("timdb", "path").help("time database generated with whenwasit"),
+		Argument::arg("part", "path").help("part converge is supposed to build"),
+	];
+	let cli = scurvy::parse(&arguments);
+
+	let content: Utf8PathBuf = cli.parse_opt_or_die("part");
+	let supporting: Vec<Utf8PathBuf> = cli.free_opts().into_iter().map(Utf8PathBuf::from).collect();
+
+	let time = std::time::Instant::now();
+	for idx in 0..100 {
+		let supporting = supporting.clone();
+		let html = process(content.clone(), supporting);
 	}
+	println!("{}ms for 100", time.elapsed().as_millis());
 
-	let content = match args.next() {
-		None => {
-			eprintln!("usage: converge <content file> [supporting files ...]");
-			return;
-		}
-		Some(path) => Utf8PathBuf::from(path),
-	};
-
-	let supporting = args.map(Utf8PathBuf::from).collect();
-
-	let html = process(content, supporting);
-	println!("{html}")
+	//println!("{html}")
 }
 
 fn process(content_file: Utf8PathBuf, mut supporting: Vec<Utf8PathBuf>) -> cutie::Html {
-	println!("{content_file}");
-	let raw = std::fs::read_to_string(&content_file).unwrap();
+	let raw = std::fs::read_to_string(content_file).unwrap();
 
 	match Part::from_str(&raw) {
 		Err(PartError::NoSetup) => cutie::Html::parse(raw),
@@ -73,7 +71,7 @@ fn process(content_file: Utf8PathBuf, mut supporting: Vec<Utf8PathBuf>) -> cutie
 					html: &'a mut cutie::Html,
 					ident: &str,
 				) -> &'a mut cutie::Tag {
-					match html.get_parent_that_contains_tag_name_mut(&ident) {
+					match html.get_parent_that_contains_tag_name_mut(ident) {
 						None => {
 							eprintln!("error processing file");
 							eprintln!("failed to find element with tag {ident}");
@@ -93,7 +91,6 @@ fn process(content_file: Utf8PathBuf, mut supporting: Vec<Utf8PathBuf>) -> cutie
 						tag.children.extend(content_html.nodes);
 					}
 					Opcode::Before => {
-						println!("BEFORE");
 						let predicate = |node: &cutie::Node| -> bool {
 							if let cutie::Node::Tag(tag) = node {
 								if tag.name == ident {
diff --git a/converge/src/timedb.rs b/converge/src/timedb.rs
new file mode 100755
index 0000000..718115d
--- /dev/null
+++ b/converge/src/timedb.rs
@@ -0,0 +1,97 @@
+use std::path::Path;
+
+use time::OffsetDateTime;
+
+#[derive(Debug)]
+pub struct TimeDb {
+	data: Vec<TimedFile>,
+}
+
+impl TimeDb {
+	pub fn load<P: AsRef<Path>>(path: P) -> Self {
+		let file = std::fs::read_to_string(path).unwrap();
+
+		let mut data = vec![];
+		for line in file.lines() {
+			let it = TimedFile::parse_line(line);
+			data.push(it);
+		}
+
+		Self { data }
+	}
+
+	pub fn get_times(&self, path: &str) -> Option<&TimedFile> {
+		for file in &self.data {
+			if &file.path == path {
+				return Some(file);
+			}
+		}
+
+		None
+	}
+}
+
+#[derive(Debug)]
+pub struct TimedFile {
+	path: String,
+	pub creation: Option<OffsetDateTime>,
+	pub modification: Option<OffsetDateTime>,
+	pub access: Option<OffsetDateTime>,
+}
+
+impl TimedFile {
+	pub fn parse_line<S: AsRef<str>>(raw: S) -> Self {
+		let mut values = raw.as_ref().rsplitn(4, ",").collect::<Vec<&str>>();
+		values.reverse();
+
+		let to_odt = |str: &&str| -> Option<OffsetDateTime> {
+			str.parse::<u64>()
+				.ok()
+				.map(|t| OffsetDateTime::from_unix_timestamp(t as i64).unwrap())
+		};
+
+		let path = unescape(values[0]);
+		let creation = values.get(1).map(to_odt).flatten();
+		let modification = values.get(2).map(to_odt).flatten();
+		let access = values.get(3).map(to_odt).flatten();
+
+		Self {
+			path,
+			creation,
+			modification,
+			access,
+		}
+	}
+}
+
+// Permissive unescape. Everything that's not \\ or \, is passed
+// unchanged, while those get their slash removed
+fn unescape<S: AsRef<str>>(raw: S) -> String {
+	let raw = raw.as_ref();
+
+	if !raw.contains('\\') {
+		return raw.to_owned();
+	}
+
+	let mut unescape = String::with_capacity(raw.len());
+	let mut escaped = false;
+	for ch in raw.chars() {
+		match (escaped, ch) {
+			(false, '\\') => {
+				escaped = true;
+			}
+			(false, c) => unescape.push(c),
+			(true, '\\') | (true, ',') => {
+				unescape.push(ch);
+				escaped = false;
+			}
+			(true, c) => {
+				unescape.push('\\');
+				unescape.push(c);
+				escaped = false;
+			}
+		}
+	}
+
+	unescape
+}