mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-03-09 20:21:06 +00:00
use ggemtext crate
This commit is contained in:
parent
fed376ea2f
commit
7f2e5d2210
@ -23,3 +23,7 @@ features = ["v4_10"]
|
||||
package = "libadwaita"
|
||||
version = "0.7.0"
|
||||
features = ["v1_6"]
|
||||
|
||||
[dependencies.gemtext]
|
||||
package = "ggemtext"
|
||||
version = "0.1.1"
|
||||
|
@ -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},
|
||||
|
@ -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