mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-01-16 01:29:57 +00:00
implement code tag parser
This commit is contained in:
parent
bb9ddda109
commit
9e9b40e3ac
@ -1,6 +1,7 @@
|
|||||||
mod parser;
|
mod parser;
|
||||||
mod widget;
|
mod widget;
|
||||||
|
|
||||||
|
use parser::code::Code;
|
||||||
use parser::header::Header;
|
use parser::header::Header;
|
||||||
use parser::link::Link;
|
use parser::link::Link;
|
||||||
use parser::list::List;
|
use parser::list::List;
|
||||||
@ -44,8 +45,95 @@ impl Reader {
|
|||||||
// Init new text buffer
|
// Init new text buffer
|
||||||
let buffer = TextBuffer::new(None);
|
let buffer = TextBuffer::new(None);
|
||||||
|
|
||||||
|
// Init multiline code builder features
|
||||||
|
let mut multiline = None;
|
||||||
|
|
||||||
// Parse gemtext lines
|
// Parse gemtext lines
|
||||||
for line in 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(&mut buffer.end_iter(), "\n");
|
||||||
|
|
||||||
|
// Skip other actions for this line
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is multiline code
|
||||||
|
match multiline {
|
||||||
|
None => {
|
||||||
|
// Open tag found
|
||||||
|
if let Some(code) = Code::multiline_begin_from(line) {
|
||||||
|
// Begin next lines collection into the code buffer
|
||||||
|
multiline = Some(code);
|
||||||
|
|
||||||
|
// Skip other actions for this line
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(ref mut this) => {
|
||||||
|
Code::multiline_continue_from(this, line);
|
||||||
|
|
||||||
|
// Close tag found:
|
||||||
|
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(&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],
|
||||||
|
);
|
||||||
|
|
||||||
|
buffer.insert(&mut buffer.end_iter(), "\n");
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
multiline = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip other actions for this line
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Is header
|
// Is header
|
||||||
if let Some(header) = Header::from(line) {
|
if let Some(header) = Header::from(line) {
|
||||||
// Build tag from level parsed
|
// Build tag from level parsed
|
||||||
@ -54,13 +142,13 @@ impl Reader {
|
|||||||
.scale(1.6)
|
.scale(1.6)
|
||||||
.sentence(true)
|
.sentence(true)
|
||||||
.weight(500)
|
.weight(500)
|
||||||
.wrap_mode(gtk::WrapMode::Word)
|
.wrap_mode(WrapMode::Word)
|
||||||
.build(),
|
.build(),
|
||||||
parser::header::Level::H2 => TextTag::builder()
|
parser::header::Level::H2 => TextTag::builder()
|
||||||
.scale(1.4)
|
.scale(1.4)
|
||||||
.sentence(true)
|
.sentence(true)
|
||||||
.weight(400)
|
.weight(400)
|
||||||
.wrap_mode(gtk::WrapMode::Word)
|
.wrap_mode(WrapMode::Word)
|
||||||
.build(),
|
.build(),
|
||||||
parser::header::Level::H3 => TextTag::builder()
|
parser::header::Level::H3 => TextTag::builder()
|
||||||
.scale(1.2)
|
.scale(1.2)
|
||||||
@ -140,7 +228,7 @@ impl Reader {
|
|||||||
.left_margin(28)
|
.left_margin(28)
|
||||||
.pixels_above_lines(4)
|
.pixels_above_lines(4)
|
||||||
.pixels_below_lines(4)
|
.pixels_below_lines(4)
|
||||||
.wrap_mode(gtk::WrapMode::Word)
|
.wrap_mode(WrapMode::Word)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register tag in buffer
|
// Register tag in buffer
|
||||||
@ -163,7 +251,7 @@ impl Reader {
|
|||||||
// Build tag from level parsed
|
// Build tag from level parsed
|
||||||
let tag = TextTag::builder()
|
let tag = TextTag::builder()
|
||||||
.style(Style::Italic)
|
.style(Style::Italic)
|
||||||
.wrap_mode(gtk::WrapMode::Word)
|
.wrap_mode(WrapMode::Word)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Register tag in buffer
|
// Register tag in buffer
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod code;
|
||||||
pub mod header;
|
pub mod header;
|
||||||
pub mod link;
|
pub mod link;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
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()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
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("```").trim();
|
||||||
|
|
||||||
|
return Some(Self {
|
||||||
|
alt: match alt.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("```").trim()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user