mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 16:45:27 +00:00
implement pre tag
This commit is contained in:
parent
0f53a899ad
commit
fb7e00758b
2 changed files with 95 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
mod bold;
|
mod bold;
|
||||||
mod code;
|
mod code;
|
||||||
mod header;
|
mod header;
|
||||||
|
mod pre;
|
||||||
mod quote;
|
mod quote;
|
||||||
mod reference;
|
mod reference;
|
||||||
mod strike;
|
mod strike;
|
||||||
|
|
@ -12,6 +13,7 @@ use bold::Bold;
|
||||||
use code::Code;
|
use code::Code;
|
||||||
use gtk::{TextBuffer, TextTag, gdk::RGBA, glib::Uri};
|
use gtk::{TextBuffer, TextTag, gdk::RGBA, glib::Uri};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
|
use pre::Pre;
|
||||||
use quote::Quote;
|
use quote::Quote;
|
||||||
use strike::Strike;
|
use strike::Strike;
|
||||||
use underline::Underline;
|
use underline::Underline;
|
||||||
|
|
@ -20,6 +22,7 @@ pub struct Tags {
|
||||||
pub bold: Bold,
|
pub bold: Bold,
|
||||||
pub code: Code,
|
pub code: Code,
|
||||||
pub header: Header,
|
pub header: Header,
|
||||||
|
pub pre: Pre,
|
||||||
pub quote: Quote,
|
pub quote: Quote,
|
||||||
pub strike: Strike,
|
pub strike: Strike,
|
||||||
pub underline: Underline,
|
pub underline: Underline,
|
||||||
|
|
@ -38,6 +41,7 @@ impl Tags {
|
||||||
bold: Bold::new(),
|
bold: Bold::new(),
|
||||||
code: Code::new(),
|
code: Code::new(),
|
||||||
header: Header::new(),
|
header: Header::new(),
|
||||||
|
pre: Pre::new(),
|
||||||
quote: Quote::new(),
|
quote: Quote::new(),
|
||||||
strike: Strike::new(),
|
strike: Strike::new(),
|
||||||
underline: Underline::new(),
|
underline: Underline::new(),
|
||||||
|
|
@ -59,6 +63,7 @@ impl Tags {
|
||||||
self.quote.render(buffer);
|
self.quote.render(buffer);
|
||||||
|
|
||||||
self.bold.render(buffer);
|
self.bold.render(buffer);
|
||||||
|
self.pre.render(buffer);
|
||||||
self.strike.render(buffer);
|
self.strike.render(buffer);
|
||||||
self.underline.render(buffer);
|
self.underline.render(buffer);
|
||||||
|
|
||||||
|
|
@ -71,6 +76,7 @@ impl Tags {
|
||||||
// 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 = pre::strip_tags(&s);
|
||||||
s = reference::strip_tags(&s);
|
s = reference::strip_tags(&s);
|
||||||
s = strike::strip_tags(&s);
|
s = strike::strip_tags(&s);
|
||||||
s = underline::strip_tags(&s);
|
s = underline::strip_tags(&s);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
use gtk::{
|
||||||
|
TextBuffer, TextTag,
|
||||||
|
WrapMode::Word,
|
||||||
|
gdk::RGBA,
|
||||||
|
prelude::{TextBufferExt, TextBufferExtManual},
|
||||||
|
};
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
const REGEX_PRE: &str = r"`(?P<text>[^`]+)`";
|
||||||
|
|
||||||
|
pub struct Pre(TextTag);
|
||||||
|
|
||||||
|
impl Pre {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(if adw::StyleManager::default().is_dark() {
|
||||||
|
TextTag::builder()
|
||||||
|
.background_rgba(&RGBA::new(0.0, 0.0, 0.0, 1.))
|
||||||
|
.foreground("#ccc")
|
||||||
|
.family("monospace") // @TODO
|
||||||
|
.wrap_mode(Word)
|
||||||
|
.build()
|
||||||
|
} else {
|
||||||
|
TextTag::builder()
|
||||||
|
.background_rgba(&RGBA::new(0.0, 0.0, 0.0, 0.06))
|
||||||
|
.family("monospace") // @TODO
|
||||||
|
.wrap_mode(Word)
|
||||||
|
.build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply preformatted `Tag` to given `TextBuffer`
|
||||||
|
pub fn render(&self, buffer: &TextBuffer) {
|
||||||
|
assert!(buffer.tag_table().add(&self.0));
|
||||||
|
|
||||||
|
let (start, end) = buffer.bounds();
|
||||||
|
let full_content = buffer.text(&start, &end, true).to_string();
|
||||||
|
|
||||||
|
let matches: Vec<_> = Regex::new(REGEX_PRE)
|
||||||
|
.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);
|
||||||
|
|
||||||
|
buffer.delete(&mut start_iter, &mut end_iter);
|
||||||
|
buffer.insert_with_tags(&mut start_iter, &cap["text"], &[&self.0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn strip_tags(value: &str) -> String {
|
||||||
|
let mut result = String::from(value);
|
||||||
|
for cap in Regex::new(REGEX_PRE).unwrap().captures_iter(value) {
|
||||||
|
if let Some(m) = cap.get(0) {
|
||||||
|
result = result.replace(m.as_str(), &cap["text"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strip_tags() {
|
||||||
|
const VALUE: &str = r"Some `pre 1` and `pre 2` with ";
|
||||||
|
let mut result = String::from(VALUE);
|
||||||
|
for cap in Regex::new(REGEX_PRE).unwrap().captures_iter(VALUE) {
|
||||||
|
if let Some(m) = cap.get(0) {
|
||||||
|
result = result.replace(m.as_str(), &cap["text"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(result, "Some pre 1 and pre 2 with ")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_regex() {
|
||||||
|
let cap: Vec<_> = Regex::new(REGEX_PRE)
|
||||||
|
.unwrap()
|
||||||
|
.captures_iter(r"Some `pre 1` and `pre 2` with ")
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(&cap.get(0).unwrap()["text"], "pre 1");
|
||||||
|
assert_eq!(&cap.get(1).unwrap()["text"], "pre 2");
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue