From 3803df72216e31af49d91e1c3f2bf64a155a2ead Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Sat, 6 Jul 2024 09:43:07 -0500 Subject: [PATCH] Stuff --- Cargo.lock | 5 +- Cargo.toml | 1 + src/main.rs | 1 + src/model.rs | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 src/model.rs diff --git a/Cargo.lock b/Cargo.lock index f790df1..087796a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1036,6 +1036,7 @@ dependencies = [ "notify", "pathdiff", "redact", + "regex", "serde", "sled", "thiserror", @@ -1512,9 +1513,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index c13b63d..f699073 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ maud = "0.26.0" notify = "6.1.1" pathdiff = "0.2.1" redact = { version = "0.1.10", features = ["serde"] } +regex = { version = "1.10.5" } serde = "1.0.201" sled = { version = "0.34.7", features = [] } thiserror = "1.0.60" diff --git a/src/main.rs b/src/main.rs index 55f6ac3..e1e3493 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod auth; mod cli; mod db; mod file_watcher; +mod model; mod observe; mod partials; mod prelude; diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 0000000..2c8f2c2 --- /dev/null +++ b/src/model.rs @@ -0,0 +1,126 @@ +mod song { + use std::{ + collections::{BTreeMap, VecDeque}, + str::FromStr, + }; + + use regex::Regex; + + pub struct Verse { + // pub background: String, // url + pub content: String, + } + + /// Sequence of verse names. + pub type SongMap = Vec; + + pub struct Song { + pub name: String, + pub verses: BTreeMap, + pub other_maps: BTreeMap, + pub default_map: SongMap, + } + + impl Song { + pub fn song_map(&self, map_name: Option) -> &Vec { + map_name + .map(|map_name| self.other_maps.get(&map_name).unwrap_or(&self.default_map)) + .unwrap_or(&self.default_map) + } + } + + #[derive(Debug)] + pub enum SongParseError { + EmptyString, + } + + const REGEX_TWO_NEWLINES_WITH_ARBITRARY_SURROUNDING_WHITESPACE: &str = r"\s*[\n\r]\s*[\n\r]\s*"; + + impl FromStr for Song { + type Err = SongParseError; + + fn from_str(s: &str) -> Result { + if s == "" { + return Err(SongParseError::EmptyString); + } + + let re = Regex::new(REGEX_TWO_NEWLINES_WITH_ARBITRARY_SURROUNDING_WHITESPACE).unwrap(); + let mut hunks = VecDeque::new(); + let mut last_end: usize = 0; + + for m in re.find_iter(s) { + hunks.push_back(&s[last_end..m.start()]); + last_end = m.end(); + } + hunks.push_back(&s[last_end..s.len() - 1]); + + // process header + let mut header_lines = hunks.pop_front().unwrap().lines(); + let name = header_lines.next().unwrap().trim().to_owned(); + + for line in header_lines { + // map(band2): slide1, slide2 + // band2: slide1, slide2 + } + + let mut verses = BTreeMap::new(); + + // process verses + for hunk in hunks { + let mut verse_contents = hunk; + let first_line = &hunk[0..hunk.find('\n').unwrap_or(hunk.len())]; + let verse_name: String = if let Some(i) = first_line.find(':') { + String::from(&first_line[0..i]) + } else { + format!("Generated Verse {}", verses.len()).to_owned() + }; + verses.insert(verse_name, verse_content); + } + + Ok(Self { + name, + verses, + other_maps: BTreeMap::new(), + default_map: vec![], + }) + } + } + + mod test { + use super::Song; + + #[test] + fn parses_simple_song() { + let song: Song = r#"Song Title + + A verse"# + .parse() + .unwrap(); + + assert_eq!(song.name, "Song Title"); + assert_eq!(song.verses.len(), 1); + } + } +} + +mod display { + use super::song::{Song, SongMap}; + + pub struct PlaylistEntry { + pub song: Song, + pub map: SongMap, + } + + pub struct PlaylistVerseRef { + pub song_index: usize, + pub song_map: String, + pub map_verse_index: usize, + } + + pub struct Display { + pub playlist: Vec<(Song, Option)>, + pub current: PlaylistVerseRef, + pub frozen_at: Option, + pub blanked: bool, + } +}