mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-03-10 04:31:14 +00:00
use ggemtext crate
This commit is contained in:
parent
fed376ea2f
commit
7f2e5d2210
@ -23,3 +23,7 @@ features = ["v4_10"]
|
|||||||
package = "libadwaita"
|
package = "libadwaita"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
features = ["v1_6"]
|
features = ["v1_6"]
|
||||||
|
|
||||||
|
[dependencies.gemtext]
|
||||||
|
package = "ggemtext"
|
||||||
|
version = "0.1.1"
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
mod parser;
|
|
||||||
mod tag;
|
mod tag;
|
||||||
mod widget;
|
mod widget;
|
||||||
|
|
||||||
use parser::{
|
use tag::Tag;
|
||||||
|
use widget::Widget;
|
||||||
|
|
||||||
|
use adw::StyleManager;
|
||||||
|
use gemtext::line::{
|
||||||
code::Code,
|
code::Code,
|
||||||
header::{Header, Level},
|
header::{Header, Level},
|
||||||
link::Link,
|
link::Link,
|
||||||
list::List,
|
list::List,
|
||||||
quote::Quote,
|
quote::Quote,
|
||||||
};
|
};
|
||||||
use tag::Tag;
|
|
||||||
use widget::Widget;
|
|
||||||
|
|
||||||
use adw::StyleManager;
|
|
||||||
use gtk::{
|
use gtk::{
|
||||||
gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY},
|
gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY},
|
||||||
gio::{Cancellable, SimpleAction},
|
gio::{Cancellable, SimpleAction},
|
||||||
|
@ -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> {
|
|
||||||
Inline::from(line)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multiline
|
|
||||||
pub fn multiline_begin_from(line: &str) -> Option<Multiline> {
|
|
||||||
Multiline::begin_from(line)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn multiline_continue_from(this: &mut Multiline, line: &str) {
|
|
||||||
Multiline::continue_from(this, line)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Self> {
|
|
||||||
// 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()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
use gtk::glib::GString;
|
|
||||||
|
|
||||||
pub struct Multiline {
|
|
||||||
pub alt: Option<GString>,
|
|
||||||
pub buffer: Vec<GString>,
|
|
||||||
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<Self> {
|
|
||||||
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("```")));
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Self> {
|
|
||||||
// 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()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
use gtk::glib::{
|
|
||||||
DateTime, GString, Regex, RegexCompileFlags, RegexMatchFlags, TimeZone, Uri, UriFlags,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Link {
|
|
||||||
pub alt: Option<GString>, // [optional] alternative link description
|
|
||||||
pub is_external: Option<bool>, // [optional] external link indication, on base option provided
|
|
||||||
pub timestamp: Option<DateTime>, // [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<Self> {
|
|
||||||
// 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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Self> {
|
|
||||||
// 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()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Self> {
|
|
||||||
// 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()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user