From ab0fa8fb141fb30b54a5d6669c74b1ef9409d5c3 Mon Sep 17 00:00:00 2001 From: yggverse Date: Tue, 15 Oct 2024 05:22:29 +0300 Subject: [PATCH] implement separated mods for tags --- .../item/page/content/text/gemini/reader.rs | 137 +++++------------- .../page/content/text/gemini/reader/tag.rs | 109 ++++++++++++++ .../content/text/gemini/reader/tag/code.rs | 23 +++ .../page/content/text/gemini/reader/tag/h1.rs | 24 +++ .../page/content/text/gemini/reader/tag/h2.rs | 24 +++ .../page/content/text/gemini/reader/tag/h3.rs | 24 +++ .../content/text/gemini/reader/tag/link.rs | 24 +++ .../content/text/gemini/reader/tag/list.rs | 24 +++ .../content/text/gemini/reader/tag/quote.rs | 22 +++ .../content/text/gemini/reader/tag/title.rs | 24 +++ 10 files changed, 331 insertions(+), 104 deletions(-) create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/code.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h1.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h2.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h3.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/link.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/list.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/quote.rs create mode 100644 src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/title.rs 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 315a0968..58ee266a 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,4 +1,5 @@ mod parser; +mod tag; mod widget; use parser::code::Code; @@ -6,14 +7,13 @@ use parser::header::Header; use parser::link::Link; use parser::list::List; use parser::quote::Quote; +use tag::Tag; use widget::Widget; -use adw::StyleManager; use gtk::{ gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY}, gio::{AppInfo, AppLaunchContext, SimpleAction}, glib::{GString, TimeZone, Uri}, - pango::Style, prelude::{ActionExt, TextBufferExt, TextBufferExtManual, TextViewExt, ToVariant, WidgetExt}, EventControllerMotion, GestureClick, TextBuffer, TextTag, TextView, TextWindowType, WrapMode, }; @@ -37,33 +37,23 @@ impl Reader { let mut title = None; // Init HashMap storage for event controllers - let mut links: HashMap = HashMap::new(); - - // Init system palette - let style = StyleManager::default(); - - // Init new text buffer - let buffer = TextBuffer::new(None); + let mut links: HashMap<&TextTag, Uri> = HashMap::new(); // Init multiline code builder features let mut multiline = None; + // Init tags + let tag = Tag::new(); + + // Init new text buffer + let buffer = TextBuffer::new(Some(tag.gobject())); + // Parse gemtext lines for line in gemtext.lines() { // Is inline code if let Some(code) = Code::inline_from(line) { - // Build tag from level parsed - let tag = TextTag::builder() - .family("monospace") - .scale(0.8) - .wrap_mode(WrapMode::None) - .build(); - - // Register tag in buffer - buffer.tag_table().add(&tag); - // Append value to buffer - buffer.insert_with_tags(&mut buffer.end_iter(), code.value.as_str(), &[&tag]); + buffer.insert_with_tags(&mut buffer.end_iter(), code.value.as_str(), &[tag.code()]); buffer.insert(&mut buffer.end_iter(), "\n"); // Skip other actions for this line @@ -89,38 +79,20 @@ impl Reader { if this.completed { // Is alt provided if let Some(alt) = &this.alt { - // Build tag for code alt description - let tag = TextTag::builder() - .pixels_above_lines(4) - .pixels_below_lines(8) - .weight(500) - .wrap_mode(WrapMode::None) - .build(); - - // Register tag in buffer - buffer.tag_table().add(&tag); - // Insert alt value to the main buffer - buffer.insert_with_tags(&mut buffer.end_iter(), alt.as_str(), &[&tag]); + buffer.insert_with_tags( + &mut buffer.end_iter(), + alt.as_str(), + &[tag.title()], + ); buffer.insert(&mut buffer.end_iter(), "\n"); } - // Build tag container for multiline code result - let tag = TextTag::builder() - .family("monospace") // @TODO does not work - .left_margin(28) - .scale(0.8) - .wrap_mode(WrapMode::None) - .build(); - - // Register tag in buffer - buffer.tag_table().add(&tag); - // Insert multiline code buffer into main buffer buffer.insert_with_tags( &mut buffer.end_iter(), &this.buffer.join("\n"), - &[&tag], + &[tag.code()], ); buffer.insert(&mut buffer.end_iter(), "\n"); @@ -136,33 +108,16 @@ impl Reader { // Is header if let Some(header) = Header::from(line) { - // Build tag from level parsed - let tag = match header.level { - parser::header::Level::H1 => TextTag::builder() - .scale(1.6) - .sentence(true) - .weight(500) - .wrap_mode(WrapMode::Word) - .build(), - parser::header::Level::H2 => TextTag::builder() - .scale(1.4) - .sentence(true) - .weight(400) - .wrap_mode(WrapMode::Word) - .build(), - parser::header::Level::H3 => TextTag::builder() - .scale(1.2) - .sentence(true) - .weight(400) - .wrap_mode(WrapMode::Word) - .build(), - }; - - // Register tag in buffer - buffer.tag_table().add(&tag); - // Append value to buffer - buffer.insert_with_tags(&mut buffer.end_iter(), header.value.as_str(), &[&tag]); + buffer.insert_with_tags( + &mut buffer.end_iter(), + header.value.as_str(), + &[match header.level { + parser::header::Level::H1 => tag.h1(), + parser::header::Level::H2 => tag.h2(), + parser::header::Level::H3 => tag.h3(), + }], + ); buffer.insert(&mut buffer.end_iter(), "\n"); // Update reader title using first gemtext header match @@ -176,18 +131,8 @@ impl Reader { // Is link if let Some(link) = Link::from(line, Some(base), Some(&TimeZone::local())) { - // Init new tag for link - let tag = TextTag::builder() - .foreground_rgba(&style.accent_color_rgba()) - .sentence(true) - .wrap_mode(WrapMode::Word) - .build(); - - // Append tag to buffer - buffer.tag_table().add(&tag); - // Append tag to HashMap storage - links.insert(tag.clone(), link.uri.clone()); + // links.insert(tag.link(), link.uri.clone()); @TODO // Create vector for alt values let mut alt = Vec::new(); @@ -214,7 +159,7 @@ impl Reader { }); // Append alt vector values to buffer - buffer.insert_with_tags(&mut buffer.end_iter(), &alt.join(" "), &[&tag]); + buffer.insert_with_tags(&mut buffer.end_iter(), &alt.join(" "), &[&tag.link()]); buffer.insert(&mut buffer.end_iter(), "\n"); // Skip other actions for this line @@ -223,22 +168,11 @@ impl Reader { // Is list if let Some(list) = List::from(line) { - // Build tag from level parsed - let tag = TextTag::builder() - .left_margin(28) - .pixels_above_lines(4) - .pixels_below_lines(4) - .wrap_mode(WrapMode::Word) - .build(); - - // Register tag in buffer - buffer.tag_table().add(&tag); - // Append value to buffer buffer.insert_with_tags( &mut buffer.end_iter(), format!("• {}", list.value).as_str(), - &[&tag], + &[&tag.list()], ); buffer.insert(&mut buffer.end_iter(), "\n"); @@ -248,17 +182,12 @@ impl Reader { // Is quote if let Some(quote) = Quote::from(line) { - // Build tag from level parsed - let tag = TextTag::builder() - .style(Style::Italic) - .wrap_mode(WrapMode::Word) - .build(); - - // Register tag in buffer - buffer.tag_table().add(&tag); - // Append value to buffer - buffer.insert_with_tags(&mut buffer.end_iter(), quote.value.as_str(), &[&tag]); + buffer.insert_with_tags( + &mut buffer.end_iter(), + quote.value.as_str(), + &[&tag.quote()], + ); buffer.insert(&mut buffer.end_iter(), "\n"); // Skip other actions for this line diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag.rs new file mode 100644 index 00000000..a97dd4db --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag.rs @@ -0,0 +1,109 @@ +mod code; +mod h1; +mod h2; +mod h3; +mod link; +mod list; +mod quote; +mod title; + +use code::Code; +use h1::H1; +use h2::H2; +use h3::H3; +use link::Link; +use list::List; +use quote::Quote; +use title::Title; + +use gtk::{TextTag, TextTagTable}; + +pub struct Tag { + gobject: TextTagTable, + // Tags + code: Code, + h1: H1, + h2: H2, + h3: H3, + link: Link, + list: List, + quote: Quote, + title: Title, +} + +impl Tag { + // Construct + pub fn new() -> Self { + // Init components + let code = Code::new(); + let h1 = H1::new(); + let h2 = H2::new(); + let h3 = H3::new(); + let link = Link::new(); + let list = List::new(); + let quote = Quote::new(); + let title = Title::new(); + + // Init tag table + let gobject = TextTagTable::new(); + + gobject.add(code.gobject()); + gobject.add(h1.gobject()); + gobject.add(h2.gobject()); + gobject.add(h3.gobject()); + gobject.add(title.gobject()); + gobject.add(link.gobject()); + gobject.add(list.gobject()); + gobject.add(quote.gobject()); + + Self { + gobject, + // Tags + code, + h1, + h2, + h3, + link, + list, + quote, + title, + } + } + + // Getters + pub fn gobject(&self) -> &TextTagTable { + &self.gobject + } + + pub fn code(&self) -> &TextTag { + &self.code.gobject() + } + + pub fn h1(&self) -> &TextTag { + &self.h1.gobject() + } + + pub fn h2(&self) -> &TextTag { + &self.h2.gobject() + } + + pub fn h3(&self) -> &TextTag { + &self.h3.gobject() + } + + pub fn link(&self) -> &TextTag { + &self.link.gobject() + } + + pub fn list(&self) -> &TextTag { + &self.list.gobject() + } + + pub fn quote(&self) -> &TextTag { + &self.quote.gobject() + } + + pub fn title(&self) -> &TextTag { + &self.title.gobject() + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/code.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/code.rs new file mode 100644 index 00000000..ac7c9c0b --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/code.rs @@ -0,0 +1,23 @@ +use gtk::{TextTag, WrapMode}; + +pub struct Code { + tag: TextTag, +} + +impl Code { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .family("monospace") // @TODO + .scale(0.8) + .wrap_mode(WrapMode::None) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h1.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h1.rs new file mode 100644 index 00000000..b0bcd9c7 --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h1.rs @@ -0,0 +1,24 @@ +use gtk::{TextTag, WrapMode}; + +pub struct H1 { + tag: TextTag, +} + +impl H1 { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .scale(1.6) + .sentence(true) + .weight(500) + .wrap_mode(WrapMode::Word) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h2.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h2.rs new file mode 100644 index 00000000..59ad3d52 --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h2.rs @@ -0,0 +1,24 @@ +use gtk::{TextTag, WrapMode}; + +pub struct H2 { + tag: TextTag, +} + +impl H2 { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .scale(1.4) + .sentence(true) + .weight(400) + .wrap_mode(WrapMode::Word) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h3.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h3.rs new file mode 100644 index 00000000..299f4dc9 --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/h3.rs @@ -0,0 +1,24 @@ +use gtk::{TextTag, WrapMode}; + +pub struct H3 { + tag: TextTag, +} + +impl H3 { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .scale(1.2) + .sentence(true) + .weight(400) + .wrap_mode(WrapMode::Word) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/link.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/link.rs new file mode 100644 index 00000000..587a63ad --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/link.rs @@ -0,0 +1,24 @@ +use adw::StyleManager; +use gtk::{TextTag, WrapMode}; + +pub struct Link { + tag: TextTag, +} + +impl Link { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .foreground_rgba(&StyleManager::default().accent_color_rgba()) // @TODO + .sentence(true) + .wrap_mode(WrapMode::Word) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/list.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/list.rs new file mode 100644 index 00000000..18962151 --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/list.rs @@ -0,0 +1,24 @@ +use gtk::{TextTag, WrapMode}; + +pub struct List { + tag: TextTag, +} + +impl List { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .left_margin(28) + .pixels_above_lines(4) + .pixels_below_lines(4) + .wrap_mode(WrapMode::Word) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/quote.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/quote.rs new file mode 100644 index 00000000..d383be35 --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/quote.rs @@ -0,0 +1,22 @@ +use gtk::{pango::Style, TextTag, WrapMode}; + +pub struct Quote { + tag: TextTag, +} + +impl Quote { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .style(Style::Italic) + .wrap_mode(WrapMode::Word) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +} diff --git a/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/title.rs b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/title.rs new file mode 100644 index 00000000..42dcdbaf --- /dev/null +++ b/src/app/browser/window/tab/item/page/content/text/gemini/reader/tag/title.rs @@ -0,0 +1,24 @@ +use gtk::{TextTag, WrapMode}; + +pub struct Title { + tag: TextTag, +} + +impl Title { + // Construct + pub fn new() -> Self { + Self { + tag: TextTag::builder() + .pixels_above_lines(4) + .pixels_below_lines(8) + .weight(500) + .wrap_mode(WrapMode::None) + .build(), + } + } + + // Getters + pub fn gobject(&self) -> &TextTag { + &self.tag + } +}