implement separated mods for tags

This commit is contained in:
yggverse 2024-10-15 05:22:29 +03:00
parent 9e9b40e3ac
commit ab0fa8fb14
10 changed files with 331 additions and 104 deletions

View File

@ -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<TextTag, Uri> = 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

View File

@ -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()
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}