diff --git a/Cargo.toml b/Cargo.toml index 832a51fa..bc2237ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,7 @@ features = ["v4_10"] package = "libadwaita" version = "0.7.0" features = ["v1_6"] + +[dependencies.gemtext] +package = "ggemtext" +version = "0.1.1" diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader.rs index ce33a151..f7d6db7b 100644 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader.rs +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader.rs @@ -1,18 +1,17 @@ -mod parser; mod tag; mod widget; -use parser::{ +use tag::Tag; +use widget::Widget; + +use adw::StyleManager; +use gemtext::line::{ code::Code, header::{Header, Level}, link::Link, list::List, quote::Quote, }; -use tag::Tag; -use widget::Widget; - -use adw::StyleManager; use gtk::{ gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY}, gio::{Cancellable, SimpleAction}, diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code.rs deleted file mode 100644 index f9ab3ee0..00000000 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code.rs +++ /dev/null @@ -1,25 +0,0 @@ -pub mod inline; -pub mod multiline; - -use inline::Inline; -use multiline::Multiline; - -pub struct Code { - // nothing yet.. -} - -impl Code { - // Inline - pub fn inline_from(line: &str) -> Option { - Inline::from(line) - } - - // Multiline - pub fn multiline_begin_from(line: &str) -> Option { - Multiline::begin_from(line) - } - - pub fn multiline_continue_from(this: &mut Multiline, line: &str) { - Multiline::continue_from(this, line) - } -} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code/inline.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code/inline.rs deleted file mode 100644 index 7baddb8c..00000000 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code/inline.rs +++ /dev/null @@ -1,29 +0,0 @@ -use gtk::glib::{GString, Regex, RegexCompileFlags, RegexMatchFlags}; - -pub struct Inline { - pub value: GString, -} - -impl Inline { - pub fn from(line: &str) -> Option { - // Parse line - let regex = Regex::split_simple( - r"^`{3}([^`]*)`{3}$", - line, - RegexCompileFlags::DEFAULT, - RegexMatchFlags::DEFAULT, - ); - - // Detect value - let value = regex.get(1)?; - - if value.trim().is_empty() { - return None; - } - - // Result - Some(Self { - value: GString::from(value.as_str()), - }) - } -} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code/multiline.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code/multiline.rs deleted file mode 100644 index 96d7c721..00000000 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/code/multiline.rs +++ /dev/null @@ -1,46 +0,0 @@ -use gtk::glib::GString; - -pub struct Multiline { - pub alt: Option, - pub buffer: Vec, - pub completed: bool, -} - -impl Multiline { - // Search in line for tag open, - // return Self constructed on success or None - pub fn begin_from(line: &str) -> Option { - if line.starts_with("```") { - let alt = line.trim_start_matches("```"); - - return Some(Self { - alt: match alt.trim().is_empty() { - true => None, - false => Some(GString::from(alt)), - }, - buffer: Vec::new(), - completed: false, - }); - } - - None - } - - // Continue preformatted buffer from line, - // set `completed` as True on close tag found - pub fn continue_from(&mut self, line: &str) { - // Make sure buffer not completed yet - if self.completed { - panic!("Could not continue as completed") // @TODO handle - } - - // Line contain close tag - if line.ends_with("```") { - self.completed = true; - } - - // Append data to the buffer, trim close tag on exists - self.buffer - .push(GString::from(line.trim_end_matches("```"))); - } -} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/header.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/header.rs deleted file mode 100644 index 24dc2482..00000000 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/header.rs +++ /dev/null @@ -1,47 +0,0 @@ -use gtk::glib::{GString, Regex, RegexCompileFlags, RegexMatchFlags}; - -pub enum Level { - H1, - H2, - H3, -} - -pub struct Header { - pub value: GString, - pub level: Level, -} - -impl Header { - pub fn from(line: &str) -> Option { - // Parse line - let regex = Regex::split_simple( - r"^(#{1,3})\s*(.+)$", - line, - RegexCompileFlags::DEFAULT, - RegexMatchFlags::DEFAULT, - ); - - // Detect header level - let level = regex.get(1)?; - - let level = match level.len() { - 1 => Level::H1, - 2 => Level::H2, - 3 => Level::H3, - _ => return None, - }; - - // Detect header value - let value = regex.get(2)?; - - if value.trim().is_empty() { - return None; - } - - // Result - Some(Self { - level, - value: GString::from(value.as_str()), - }) - } -} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/link.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/link.rs deleted file mode 100644 index b1d99e2e..00000000 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/link.rs +++ /dev/null @@ -1,89 +0,0 @@ -use gtk::glib::{ - DateTime, GString, Regex, RegexCompileFlags, RegexMatchFlags, TimeZone, Uri, UriFlags, -}; - -pub struct Link { - pub alt: Option, // [optional] alternative link description - pub is_external: Option, // [optional] external link indication, on base option provided - pub timestamp: Option, // [optional] valid link DateTime object - pub uri: Uri, // [required] valid link URI object -} - -impl Link { - pub fn from(line: &str, base: Option<&Uri>, timezone: Option<&TimeZone>) -> Option { - // Define initial values - let mut alt = None; - let mut timestamp = None; - let mut is_external = None; - - // Begin line parse - let regex = Regex::split_simple( - r"^=>\s*([^\s]+)\s*(\d{4}-\d{2}-\d{2})?\s*(.+)?$", - line, - RegexCompileFlags::DEFAULT, - RegexMatchFlags::DEFAULT, - ); - - // Detect address required to continue - let unresolved_address = regex.get(1)?; - - // Convert address to the valid URI - let uri = match base { - // Base conversion requested - Some(base_uri) => { - // Convert relative address to absolute - match Uri::resolve_relative( - Some(&base_uri.to_str()), - unresolved_address.as_str(), - UriFlags::NONE, - ) { - Ok(resolved_str) => { - // Try convert string to the valid URI - match Uri::parse(&resolved_str, UriFlags::NONE) { - Ok(resolved_uri) => { - // Change external status - is_external = Some(resolved_uri.scheme() != base_uri.scheme()); - - // Result - resolved_uri - } - Err(_) => return None, - } - } - Err(_) => return None, - } - } - // Base resolve not requested - None => { - // Just try convert address to valid URI - match Uri::parse(&unresolved_address, UriFlags::NONE) { - Ok(unresolved_uri) => unresolved_uri, - Err(_) => return None, - } - } - }; - - // Timestamp - if let Some(date) = regex.get(2) { - // @TODO even possible, but simpler to work with `DateTime` API - // await for new features in `Date` as better in Gemini context - // https://docs.gtk.org/glib/struct.Date.html - timestamp = match DateTime::from_iso8601(&format!("{date}T00:00:00"), timezone) { - Ok(value) => Some(value), - Err(_) => None, - } - } - - // Alt - if let Some(value) = regex.get(3) { - alt = Some(GString::from(value.as_str())) - }; - - Some(Self { - alt, - is_external, - timestamp, - uri, - }) - } -} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/list.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/list.rs deleted file mode 100644 index f2598e5d..00000000 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/list.rs +++ /dev/null @@ -1,29 +0,0 @@ -use gtk::glib::{GString, Regex, RegexCompileFlags, RegexMatchFlags}; - -pub struct List { - pub value: GString, -} - -impl List { - pub fn from(line: &str) -> Option { - // Parse line - let regex = Regex::split_simple( - r"^\*\s*(.+)$", - line, - RegexCompileFlags::DEFAULT, - RegexMatchFlags::DEFAULT, - ); - - // Detect value - let value = regex.get(1)?; - - if value.trim().is_empty() { - return None; - } - - // Result - Some(Self { - value: GString::from(value.as_str()), - }) - } -} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/quote.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/quote.rs deleted file mode 100644 index 20d69b6c..00000000 --- a/src/app/browser/window/tab/item/page/content/text/gemini/reader/parser/quote.rs +++ /dev/null @@ -1,29 +0,0 @@ -use gtk::glib::{GString, Regex, RegexCompileFlags, RegexMatchFlags}; - -pub struct Quote { - pub value: GString, -} - -impl Quote { - pub fn from(line: &str) -> Option { - // Parse line - let regex = Regex::split_simple( - r"^>\s*(.+)$", - line, - RegexCompileFlags::DEFAULT, - RegexMatchFlags::DEFAULT, - ); - - // Detect value - let value = regex.get(1)?; - - if value.trim().is_empty() { - return None; - } - - // Result - Some(Self { - value: GString::from(value.as_str()), - }) - } -}