diff --git a/src/main.rs b/src/main.rs index 4b58ec0..24e33d1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ #![feature(iter_map_windows)] use iced::{ - Element, - widget::{self, column, combo_box}, + clipboard, widget::{self, column, combo_box, row, text_input}, Element, Task }; use std::{env, fs, path::PathBuf}; use texts::*; @@ -11,6 +10,7 @@ mod texts; pub const BIBLE_DIRECTORY: &str = "./Holy-Bible-XML-Format"; fn main() -> iced::Result { + // CLI let arg = env::args().collect::>(); if let Some(query) = arg.get(1) { if query.starts_with("H") | query.starts_with("h") { @@ -20,33 +20,38 @@ fn main() -> iced::Result { } } if let Some(second_query) = arg.get(2) { - if let Some(f) = bible::get( - query, - second_query, - vec![format!("{BIBLE_DIRECTORY}/EnglishNASBBible.xml").into()], - ) { - println!("{}", f); - } + // if let Some(f) = bible::get( query, second_query, vec![format!("{BIBLE_DIRECTORY}/EnglishNASBBible.xml").into()], + // ) { + // println!("{}", f); + // } return Ok(()) } } + // GUI iced::run("Bible Search", State::update, State::view) } #[derive(Debug, Clone)] enum Message { - InputChange(String), + BibleSearchInput(String), BibleSelected(String), - SubmitQuery, + BibleSearchSubmit, + CopyText, + Clear, + WordSearchInput(String), + SubmitWordSearch, } struct State { files: combo_box::State, - file_selected: Option, + selected_file: Option, + bible_selected: Option, - query: String, + bible_search: String, body: Option, + + word_search: String, } impl Default for State { fn default() -> Self { @@ -74,55 +79,88 @@ impl Default for State { Self { files: combo_box::State::new(files), - file_selected: None, + selected_file: None, + bible_selected: None, - query: String::new(), + bible_search: String::new(), body: None, + + word_search: String::new(), } } } impl State { - fn update(&mut self, msg: Message) { + fn update(&mut self, msg: Message) -> Task { match msg { Message::BibleSelected(file) => { - self.file_selected = Some(file); + if let Ok(contents) = fs::read_to_string(&file) { + if let Ok(bible) = quick_xml::de::from_str::(&contents) { + // State is held technically in this variable, although + // the Bible is held in memory in it's own variable. + self.selected_file = Some(format!("{bible}")); + self.bible_selected = Some(bible); + // automatically focus the search bar when done here + return text_input::focus("bible-search"); + } + } } - Message::InputChange(query) => { - // update self's state - self.query = query; - } - Message::SubmitQuery => { - let mut splits = self.query.split_whitespace(); + Message::BibleSearchInput(query) => self.bible_search = query, + Message::WordSearchInput(query) => self.word_search = query, + Message::BibleSearchSubmit => { + let mut splits = self.bible_search.split_whitespace(); let book = splits.next(); let location = splits.next(); - if let (Some(book), Some(chap_and_ver), Some(file)) = - (book, location, &self.file_selected) + if let (Some(book), Some(chap_and_ver), Some(bible)) = + (book, location, &self.bible_selected) { - self.body = bible::get(book, chap_and_ver, vec![file.into()]); + self.body = bible::get(book, chap_and_ver, vec![bible]); } } - } + Message::SubmitWordSearch => { + println!("todo: search for {}", self.word_search); + } + Message::CopyText => { + if let Some(text) = &self.body { + return clipboard::write::(parse(text)); + } + } + Message::Clear => { + self.body = None; + self.bible_search = String::new(); + return text_input::focus("bible-search"); + } + }; + Task::none() } fn view(&self) -> Element { let msg = if let Some(body) = self.body.clone() { parse(&body) } else { - "None".to_string() + String::new() }; column![ widget::combo_box( &self.files, "Select Bible", - self.file_selected.as_ref(), + self.selected_file.as_ref(), Message::BibleSelected ), - widget::text_input("Search query, ie: Gen 1:1", &self.query) - .on_input(Message::InputChange) - .on_submit(Message::SubmitQuery), + widget::text_input("Search query, ie: Gen 1:1", &self.bible_search) + .on_input(Message::BibleSearchInput) + .on_submit(Message::BibleSearchSubmit) + .id("bible-search"), + widget::text_input("Word Search", &self.word_search) + .on_input(Message::WordSearchInput) + .on_submit(Message::SubmitWordSearch) + .id("word-search"), + row![ + widget::button("Copy").on_press(Message::CopyText), + widget::button("Clear").on_press(Message::Clear), + ], widget::text(msg), ] .into() @@ -135,7 +173,7 @@ fn parse(input: &str) -> String { .bytes() .into_iter() .enumerate() - .map_windows(|[(ai, a), (bi, b)]| { + .map_windows(|[(ai, a), (_, b)]| { // 27 91 is the start sequence for a color/style if *a == 27 && *b == 91 { Some(*ai) @@ -208,3 +246,4 @@ fn parse(input: &str) -> String { modified } + diff --git a/src/texts/bible.rs b/src/texts/bible.rs index f771c02..b49533f 100644 --- a/src/texts/bible.rs +++ b/src/texts/bible.rs @@ -1,7 +1,6 @@ use inline_colorization::*; -use std::{fmt::Display, fs, path::PathBuf}; +use std::fmt::Display; -use quick_xml::de::from_str; use serde::Deserialize; pub const BOOKS_IN_ORDER: [&str; 66] = [ @@ -73,7 +72,11 @@ pub const BOOKS_IN_ORDER: [&str; 66] = [ "Revelation", ]; -pub fn get(book: &str, chap_and_ver: &str, from_files: Vec) -> Option { +pub fn search_for_word(word: &str, from_files: &Bible) -> Vec { + todo!() +} + +pub fn get(book: &str, chap_and_ver: &str, bibles: Vec<&Bible>) -> Option { // expecting query to be in format: // Gen 1:2 // Gen 1:2-5 @@ -89,7 +92,7 @@ pub fn get(book: &str, chap_and_ver: &str, from_files: Vec) -> Option>(); let (book_idx, book_name) = match res.len() { @@ -107,19 +110,13 @@ pub fn get(book: &str, chap_and_ver: &str, from_files: Vec) -> Option(&contents).ok()) - .collect::>(); // Select the book in each Bible let books = bibles .iter() // Book are 1 indexed in the xml spec .map(|bible| (bible, bible.get_book_by_index(book_idx + 1))) .filter(|(_,e)| e.is_some()) - .map(|(bible,book)| (bible,book.unwrap())) + .map(|(bible,book)| (*bible,book.unwrap())) .collect::>(); // Select the chapter in each Bible @@ -237,12 +234,17 @@ impl Chapter { } #[derive(Deserialize)] -struct Bible { +pub struct Bible { #[serde(rename = "@translation")] translation_name: String, #[serde(rename = "testament")] testaments: Vec, } +impl Display for Bible { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}",self.translation_name) + } +} #[derive(Deserialize)] struct Testament {