implement 1-6 level header tags

This commit is contained in:
yggverse 2026-03-08 05:04:50 +02:00
parent 191057cc50
commit 31346d1d63
3 changed files with 82 additions and 22 deletions

View file

@ -37,8 +37,22 @@ impl Markdown {
pub fn build(
(window_action, item_action): (&Rc<WindowAction>, &Rc<ItemAction>),
base: &Uri,
gemtext: &str,
markdown: &str,
) -> Result<Self, Error> {
/// Header tag
fn header(buffer: &TextBuffer, tag: &TextTag, line: &str, pattern: &str) -> Option<String> {
if let Some(h) = line.trim_start().strip_prefix(pattern)
&& !h.starts_with(pattern)
{
let header = h.trim();
buffer.insert_with_tags(&mut buffer.end_iter(), header, &[tag]);
buffer.insert(&mut buffer.end_iter(), NEW_LINE);
Some(header.into())
} else {
None
}
}
// Init default values
let mut title = None;
@ -98,7 +112,7 @@ impl Markdown {
let is_code_enabled = {
use ggemtext::line::code::{self};
let mut t: usize = 0;
for l in gemtext.lines() {
for l in markdown.lines() {
if l.starts_with(code::TAG) {
t += 1;
}
@ -106,8 +120,8 @@ impl Markdown {
t == 0 || t.is_multiple_of(2)
};
// Parse gemtext lines
for line in gemtext.lines() {
// Parse markdown lines
'l: for line in markdown.lines() {
if is_code_enabled {
use ggemtext::line::Code;
match code {
@ -192,25 +206,27 @@ impl Markdown {
}
}
// Is header
{
use ggemtext::line::{Header, header::Level};
if let Some(header) = Header::parse(line) {
buffer.insert_with_tags(
&mut buffer.end_iter(),
&header.value,
&[match header.level {
Level::H1 => &tag.h1,
Level::H2 => &tag.h2,
Level::H3 => &tag.h3,
}],
);
buffer.insert(&mut buffer.end_iter(), NEW_LINE);
// Is 1-6 level header
for level in 1..=6 {
if let Some(t) = header(
&buffer,
match level {
1 => &tag.h1,
2 => &tag.h2,
3 => &tag.h3,
4 => &tag.h4,
5 => &tag.h5,
6 => &tag.h6,
_ => unreachable!(),
},
line,
&H.repeat(level),
) {
// Update document title by tag, if not set before
if title.is_none() {
title = Some(header.value.clone());
title = Some(t);
}
continue;
continue 'l;
}
}
@ -521,7 +537,7 @@ impl Markdown {
Ok(Self { text_view, title })
} else {
Err(Error::Markup(
"Invalid multiline markup! Gemtext format partially ignored.".to_string(),
"Invalid multiline markup! Markdown format partially ignored.".to_string(),
Self { text_view, title },
))
}
@ -582,3 +598,5 @@ fn link_prefix(request: String, prefix: &str) -> String {
const LINK_PREFIX_DOWNLOAD: &str = "download:";
const LINK_PREFIX_SOURCE: &str = "source:";
const H: &str = "#";

View file

@ -17,6 +17,9 @@ pub struct Tag {
pub h1: TextTag,
pub h2: TextTag,
pub h3: TextTag,
pub h4: TextTag,
pub h5: TextTag,
pub h6: TextTag,
pub list: TextTag,
pub quote: TextTag,
pub title: TextTag,
@ -36,6 +39,9 @@ impl Tag {
let h1 = TextTag::h1();
let h2 = TextTag::h2();
let h3 = TextTag::h3();
let h4 = TextTag::h4();
let h5 = TextTag::h5();
let h6 = TextTag::h6();
let list = TextTag::list();
let quote = TextTag::quote();
let title = TextTag::title();
@ -47,6 +53,9 @@ impl Tag {
text_tag_table.add(&h1);
text_tag_table.add(&h2);
text_tag_table.add(&h3);
text_tag_table.add(&h4);
text_tag_table.add(&h5);
text_tag_table.add(&h6);
text_tag_table.add(&title);
text_tag_table.add(&list);
text_tag_table.add(&quote);
@ -58,6 +67,9 @@ impl Tag {
h1,
h2,
h3,
h4,
h5,
h6,
list,
quote,
title,

View file

@ -4,6 +4,9 @@ pub trait Header {
fn h1() -> Self;
fn h2() -> Self;
fn h3() -> Self;
fn h4() -> Self;
fn h5() -> Self;
fn h6() -> Self;
}
impl Header for TextTag {
@ -34,4 +37,31 @@ impl Header for TextTag {
.wrap_mode(WrapMode::Word)
.build()
}
fn h4() -> Self {
TextTag::builder()
.foreground("#c88800") // @TODO optional
.scale(1.1)
.sentence(true)
.weight(400)
.wrap_mode(WrapMode::Word)
.build()
}
fn h5() -> Self {
TextTag::builder()
.foreground("#c88800") // @TODO optional
.scale(1.0)
.sentence(true)
.weight(400)
.wrap_mode(WrapMode::Word)
.build()
}
fn h6() -> Self {
TextTag::builder()
.foreground("#c88800") // @TODO optional
.scale(1.0)
.sentence(true)
.weight(300)
.wrap_mode(WrapMode::Word)
.build()
}
}