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);
|
||||
|
||||
// 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)
|
||||
let action_header_copy_url =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
mod bold;
|
||||
mod code;
|
||||
mod header;
|
||||
mod hr;
|
||||
mod list;
|
||||
mod pre;
|
||||
mod quote;
|
||||
|
|
@ -11,10 +12,10 @@ mod underline;
|
|||
use bold::Bold;
|
||||
use code::Code;
|
||||
use gtk::{
|
||||
TextBuffer, TextSearchFlags, TextTag,
|
||||
TextSearchFlags, TextTag, TextView,
|
||||
gdk::RGBA,
|
||||
glib::{GString, Uri},
|
||||
prelude::TextBufferExt,
|
||||
prelude::{TextBufferExt, TextViewExt},
|
||||
};
|
||||
use header::Header;
|
||||
use pre::Pre;
|
||||
|
|
@ -54,31 +55,32 @@ impl Tags {
|
|||
}
|
||||
pub fn render(
|
||||
&mut self,
|
||||
buffer: &TextBuffer,
|
||||
text_view: &TextView,
|
||||
base: &Uri,
|
||||
link_color: &RGBA,
|
||||
links: &mut HashMap<TextTag, Uri>,
|
||||
headers: &mut HashMap<TextTag, (String, Uri)>,
|
||||
) -> Option<String> {
|
||||
let buffer = text_view.buffer();
|
||||
|
||||
// Collect all code blocks first,
|
||||
// and temporarily replace them with placeholder ID
|
||||
self.code.collect(buffer);
|
||||
self.code.collect(&buffer);
|
||||
|
||||
// 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.pre.render(buffer);
|
||||
self.strike.render(buffer);
|
||||
self.underline.render(buffer);
|
||||
self.bold.render(&buffer);
|
||||
self.pre.render(&buffer);
|
||||
self.strike.render(&buffer);
|
||||
self.underline.render(&buffer);
|
||||
|
||||
reference::render_images_links(buffer, base, link_color, links);
|
||||
reference::render_images(buffer, base, link_color, links);
|
||||
reference::render_links(buffer, base, link_color, links);
|
||||
reference::render(&buffer, base, link_color, links);
|
||||
hr::render(text_view);
|
||||
|
||||
// Cleanup unformatted escape chars
|
||||
for e in ESCAPE_ENTRIES {
|
||||
|
|
@ -94,11 +96,12 @@ impl Tags {
|
|||
}
|
||||
|
||||
// Render placeholders
|
||||
self.code.render(buffer);
|
||||
self.code.render(&buffer);
|
||||
|
||||
// Format document title string
|
||||
title.map(|mut s| {
|
||||
s = bold::strip_tags(&s);
|
||||
s = hr::strip_tags(&s);
|
||||
s = pre::strip_tags(&s);
|
||||
s = reference::strip_tags(&s);
|
||||
s = strike::strip_tags(&s);
|
||||
|
|
@ -118,10 +121,13 @@ pub fn format_header_fragment(value: &str) -> GString {
|
|||
|
||||
const ESCAPE_ENTRIES: &[&str] = &[
|
||||
"\\\n", "\\\\", "\\>", "\\`", "\\!", "\\[", "\\]", "\\(", "\\)", "\\*", "\\#", "\\~", "\\_",
|
||||
"\\-",
|
||||
];
|
||||
#[test]
|
||||
fn test_escape_entries() {
|
||||
let mut set = std::collections::HashSet::new();
|
||||
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 `[![]()]()`
|
||||
pub fn render_images_links(
|
||||
fn render_images_links(
|
||||
buffer: &TextBuffer,
|
||||
base: &Uri,
|
||||
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 `![]()`
|
||||
pub fn render_images(
|
||||
fn render_images(
|
||||
buffer: &TextBuffer,
|
||||
base: &Uri,
|
||||
link_color: &RGBA,
|
||||
|
|
@ -211,7 +223,7 @@ pub fn render_images(
|
|||
}
|
||||
}
|
||||
/// Links `[]()`
|
||||
pub fn render_links(
|
||||
fn render_links(
|
||||
buffer: &TextBuffer,
|
||||
base: &Uri,
|
||||
link_color: &RGBA,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue