mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 08:35:28 +00:00
add missed hr tag support, minor reference api updates
This commit is contained in:
parent
86ce8ceff5
commit
b6b8f96bba
4 changed files with 131 additions and 20 deletions
|
|
@ -76,7 +76,7 @@ impl Markdown {
|
||||||
let gutter = Gutter::build(&text_view);
|
let gutter = Gutter::build(&text_view);
|
||||||
|
|
||||||
// Render markdown tags
|
// Render markdown tags
|
||||||
let title = tags.render(&buffer, base, &link_color.0, &mut links, &mut headers);
|
let title = tags.render(&text_view, base, &link_color.0, &mut links, &mut headers);
|
||||||
|
|
||||||
// Headers context menu (fragment capture)
|
// Headers context menu (fragment capture)
|
||||||
let action_header_copy_url =
|
let action_header_copy_url =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
mod bold;
|
mod bold;
|
||||||
mod code;
|
mod code;
|
||||||
mod header;
|
mod header;
|
||||||
|
mod hr;
|
||||||
mod list;
|
mod list;
|
||||||
mod pre;
|
mod pre;
|
||||||
mod quote;
|
mod quote;
|
||||||
|
|
@ -11,10 +12,10 @@ mod underline;
|
||||||
use bold::Bold;
|
use bold::Bold;
|
||||||
use code::Code;
|
use code::Code;
|
||||||
use gtk::{
|
use gtk::{
|
||||||
TextBuffer, TextSearchFlags, TextTag,
|
TextSearchFlags, TextTag, TextView,
|
||||||
gdk::RGBA,
|
gdk::RGBA,
|
||||||
glib::{GString, Uri},
|
glib::{GString, Uri},
|
||||||
prelude::TextBufferExt,
|
prelude::{TextBufferExt, TextViewExt},
|
||||||
};
|
};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use pre::Pre;
|
use pre::Pre;
|
||||||
|
|
@ -54,31 +55,32 @@ impl Tags {
|
||||||
}
|
}
|
||||||
pub fn render(
|
pub fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &TextBuffer,
|
text_view: &TextView,
|
||||||
base: &Uri,
|
base: &Uri,
|
||||||
link_color: &RGBA,
|
link_color: &RGBA,
|
||||||
links: &mut HashMap<TextTag, Uri>,
|
links: &mut HashMap<TextTag, Uri>,
|
||||||
headers: &mut HashMap<TextTag, (String, Uri)>,
|
headers: &mut HashMap<TextTag, (String, Uri)>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
|
let buffer = text_view.buffer();
|
||||||
|
|
||||||
// Collect all code blocks first,
|
// Collect all code blocks first,
|
||||||
// and temporarily replace them with placeholder ID
|
// and temporarily replace them with placeholder ID
|
||||||
self.code.collect(buffer);
|
self.code.collect(&buffer);
|
||||||
|
|
||||||
// Keep in order!
|
// Keep in order!
|
||||||
let title = self.header.render(buffer, base, headers);
|
let title = self.header.render(&buffer, base, headers);
|
||||||
|
|
||||||
list::render(buffer);
|
list::render(&buffer);
|
||||||
|
|
||||||
self.quote.render(buffer);
|
self.quote.render(&buffer);
|
||||||
|
|
||||||
self.bold.render(buffer);
|
self.bold.render(&buffer);
|
||||||
self.pre.render(buffer);
|
self.pre.render(&buffer);
|
||||||
self.strike.render(buffer);
|
self.strike.render(&buffer);
|
||||||
self.underline.render(buffer);
|
self.underline.render(&buffer);
|
||||||
|
|
||||||
reference::render_images_links(buffer, base, link_color, links);
|
reference::render(&buffer, base, link_color, links);
|
||||||
reference::render_images(buffer, base, link_color, links);
|
hr::render(text_view);
|
||||||
reference::render_links(buffer, base, link_color, links);
|
|
||||||
|
|
||||||
// Cleanup unformatted escape chars
|
// Cleanup unformatted escape chars
|
||||||
for e in ESCAPE_ENTRIES {
|
for e in ESCAPE_ENTRIES {
|
||||||
|
|
@ -94,11 +96,12 @@ impl Tags {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render placeholders
|
// Render placeholders
|
||||||
self.code.render(buffer);
|
self.code.render(&buffer);
|
||||||
|
|
||||||
// Format document title string
|
// Format document title string
|
||||||
title.map(|mut s| {
|
title.map(|mut s| {
|
||||||
s = bold::strip_tags(&s);
|
s = bold::strip_tags(&s);
|
||||||
|
s = hr::strip_tags(&s);
|
||||||
s = pre::strip_tags(&s);
|
s = pre::strip_tags(&s);
|
||||||
s = reference::strip_tags(&s);
|
s = reference::strip_tags(&s);
|
||||||
s = strike::strip_tags(&s);
|
s = strike::strip_tags(&s);
|
||||||
|
|
@ -118,10 +121,13 @@ pub fn format_header_fragment(value: &str) -> GString {
|
||||||
|
|
||||||
const ESCAPE_ENTRIES: &[&str] = &[
|
const ESCAPE_ENTRIES: &[&str] = &[
|
||||||
"\\\n", "\\\\", "\\>", "\\`", "\\!", "\\[", "\\]", "\\(", "\\)", "\\*", "\\#", "\\~", "\\_",
|
"\\\n", "\\\\", "\\>", "\\`", "\\!", "\\[", "\\]", "\\(", "\\)", "\\*", "\\#", "\\~", "\\_",
|
||||||
|
"\\-",
|
||||||
];
|
];
|
||||||
#[test]
|
#[test]
|
||||||
fn test_escape_entries() {
|
fn test_escape_entries() {
|
||||||
|
let mut set = std::collections::HashSet::new();
|
||||||
for e in ESCAPE_ENTRIES {
|
for e in ESCAPE_ENTRIES {
|
||||||
assert_eq!(e.len(), 2)
|
assert_eq!(e.len(), 2);
|
||||||
|
assert!(set.insert(*e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
use gtk::{
|
||||||
|
Orientation, Separator, TextView,
|
||||||
|
glib::{ControlFlow, idle_add_local},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
const REGEX_HR: &str = r"(?m)^(?P<hr>\\?[-]{3,})$";
|
||||||
|
|
||||||
|
/// Apply --- `Tag` to given `TextBuffer`
|
||||||
|
pub fn render(text_view: &TextView) {
|
||||||
|
let separator = Separator::builder()
|
||||||
|
.orientation(Orientation::Horizontal)
|
||||||
|
.build();
|
||||||
|
idle_add_local({
|
||||||
|
let text_view = text_view.clone();
|
||||||
|
let separator = separator.clone();
|
||||||
|
move || {
|
||||||
|
separator.set_width_request(text_view.width() - 18);
|
||||||
|
ControlFlow::Break
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let buffer = text_view.buffer();
|
||||||
|
|
||||||
|
let (start, end) = buffer.bounds();
|
||||||
|
let full_content = buffer.text(&start, &end, true).to_string();
|
||||||
|
|
||||||
|
let matches: Vec<_> = Regex::new(REGEX_HR)
|
||||||
|
.unwrap()
|
||||||
|
.captures_iter(&full_content)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for cap in matches.into_iter().rev() {
|
||||||
|
let full_match = cap.get(0).unwrap();
|
||||||
|
|
||||||
|
let start_char_offset = full_content[..full_match.start()].chars().count() as i32;
|
||||||
|
let end_char_offset = full_content[..full_match.end()].chars().count() as i32;
|
||||||
|
|
||||||
|
let mut start_iter = buffer.iter_at_offset(start_char_offset);
|
||||||
|
let mut end_iter = buffer.iter_at_offset(end_char_offset);
|
||||||
|
|
||||||
|
if start_char_offset > 0
|
||||||
|
&& buffer
|
||||||
|
.text(
|
||||||
|
&buffer.iter_at_offset(start_char_offset - 1),
|
||||||
|
&end_iter,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.contains("\\")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.delete(&mut start_iter, &mut end_iter);
|
||||||
|
text_view.add_child_at_anchor(&separator, &buffer.create_child_anchor(&mut end_iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn strip_tags(value: &str) -> String {
|
||||||
|
let mut result = String::from(value);
|
||||||
|
for cap in Regex::new(REGEX_HR).unwrap().captures_iter(value) {
|
||||||
|
if let Some(m) = cap.get(0) {
|
||||||
|
result = result.replace(m.as_str(), &cap["hr"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_tags() {
|
||||||
|
const VALUE: &str = "Some line\n---\nSome another-line with ";
|
||||||
|
let mut result = String::from(VALUE);
|
||||||
|
for cap in Regex::new(REGEX_HR).unwrap().captures_iter(VALUE) {
|
||||||
|
if let Some(m) = cap.get(0) {
|
||||||
|
result = result.replace(m.as_str(), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
"Some line\n\nSome another-line with "
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_regex() {
|
||||||
|
let cap: Vec<_> = Regex::new(REGEX_HR)
|
||||||
|
.unwrap()
|
||||||
|
.captures_iter("Some line\n---\nSome another-line with ")
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(&cap.first().unwrap()["hr"], "---");
|
||||||
|
}
|
||||||
|
|
@ -106,7 +106,7 @@ impl Reference {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Image links `[![]()]()`
|
/// Image links `[![]()]()`
|
||||||
pub fn render_images_links(
|
fn render_images_links(
|
||||||
buffer: &TextBuffer,
|
buffer: &TextBuffer,
|
||||||
base: &Uri,
|
base: &Uri,
|
||||||
link_color: &RGBA,
|
link_color: &RGBA,
|
||||||
|
|
@ -159,8 +159,20 @@ pub fn render_images_links(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render(
|
||||||
|
buffer: &TextBuffer,
|
||||||
|
base: &Uri,
|
||||||
|
link_color: &RGBA,
|
||||||
|
links: &mut HashMap<TextTag, Uri>,
|
||||||
|
) {
|
||||||
|
render_images_links(buffer, base, link_color, links);
|
||||||
|
render_images(buffer, base, link_color, links);
|
||||||
|
render_links(buffer, base, link_color, links)
|
||||||
|
}
|
||||||
|
|
||||||
/// Image tags `![]()`
|
/// Image tags `![]()`
|
||||||
pub fn render_images(
|
fn render_images(
|
||||||
buffer: &TextBuffer,
|
buffer: &TextBuffer,
|
||||||
base: &Uri,
|
base: &Uri,
|
||||||
link_color: &RGBA,
|
link_color: &RGBA,
|
||||||
|
|
@ -211,7 +223,7 @@ pub fn render_images(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Links `[]()`
|
/// Links `[]()`
|
||||||
pub fn render_links(
|
fn render_links(
|
||||||
buffer: &TextBuffer,
|
buffer: &TextBuffer,
|
||||||
base: &Uri,
|
base: &Uri,
|
||||||
link_color: &RGBA,
|
link_color: &RGBA,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue