Skip to content

Commit 7802869

Browse files
author
yggverse
committed
remove regex dependency, rename constructor, implement Gemtext trait
1 parent 9d27cdf commit 7802869

File tree

2 files changed

+70
-20
lines changed

2 files changed

+70
-20
lines changed

src/line/header.rs

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use glib::{Regex, RegexCompileFlags, RegexMatchFlags};
1+
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) tag
2+
/// * store as entire static chars array
3+
pub const TAG_H1: &str = "#";
4+
pub const TAG_H2: &str = "##";
5+
pub const TAG_H3: &str = "###";
26

37
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) type holder
48
pub enum Level {
@@ -9,32 +13,78 @@ pub enum Level {
913

1014
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) entity holder
1115
pub struct Header {
12-
pub value: String,
1316
pub level: Level,
17+
pub value: String,
1418
}
1519

1620
impl Header {
1721
// Constructors
1822

1923
/// Parse `Self` from line string
20-
pub fn from(line: &str) -> Option<Self> {
21-
// Parse line
22-
let regex = Regex::split_simple(
23-
r"^(#{1,3})\s*(.+)$",
24-
line,
25-
RegexCompileFlags::DEFAULT,
26-
RegexMatchFlags::DEFAULT,
27-
);
28-
29-
// Result
24+
pub fn parse(line: &str) -> Option<Self> {
3025
Some(Self {
31-
level: match regex.get(1)?.len() {
32-
1 => Level::H1,
33-
2 => Level::H2,
34-
3 => Level::H3,
35-
_ => return None,
36-
},
37-
value: regex.get(2)?.trim().to_string(),
26+
level: line.to_level()?,
27+
value: line.as_value()?.to_string(),
3828
})
3929
}
30+
31+
// Converters
32+
33+
/// Convert `Self` to [Gemtext](https://geminiprotocol.net/docs/gemtext-specification.gmi) line
34+
pub fn to_source(&self) -> String {
35+
self.value.to_source(&self.level)
36+
}
37+
}
38+
39+
pub trait Gemtext {
40+
/// Get [Gemtext](https://geminiprotocol.net/docs/gemtext-specification.gmi) value from `Self`
41+
fn as_value(&self) -> Option<&Self>;
42+
/// Convert `Self` to `Level`
43+
fn to_level(&self) -> Option<Level>;
44+
/// Convert `Self` to [Gemtext](https://geminiprotocol.net/docs/gemtext-specification.gmi) line
45+
fn to_source(&self, level: &Level) -> String;
46+
}
47+
48+
impl Gemtext for str {
49+
fn as_value(&self) -> Option<&Self> {
50+
if let Some(h3) = self.strip_prefix(TAG_H3) {
51+
if h3.trim_start().starts_with(TAG_H1) {
52+
return None; // H4+
53+
}
54+
return Some(h3.trim());
55+
}
56+
if let Some(h2) = self.strip_prefix(TAG_H2) {
57+
return Some(h2.trim());
58+
}
59+
if let Some(h1) = self.strip_prefix(TAG_H1) {
60+
return Some(h1.trim());
61+
}
62+
None
63+
}
64+
fn to_level(&self) -> Option<Level> {
65+
if let Some(h3) = self.strip_prefix(TAG_H3) {
66+
if h3.trim_start().starts_with(TAG_H1) {
67+
return None; // H4+
68+
}
69+
return Some(Level::H3);
70+
}
71+
if self.starts_with(TAG_H2) {
72+
return Some(Level::H2);
73+
}
74+
if self.starts_with(TAG_H1) {
75+
return Some(Level::H1);
76+
}
77+
None
78+
}
79+
fn to_source(&self, level: &Level) -> String {
80+
format!(
81+
"{} {}",
82+
match level {
83+
Level::H1 => TAG_H1,
84+
Level::H2 => TAG_H2,
85+
Level::H3 => TAG_H3,
86+
},
87+
self.trim()
88+
)
89+
}
4090
}

tests/integration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn gemtext() {
6060
};
6161

6262
// Header
63-
if let Some(result) = Header::from(line) {
63+
if let Some(result) = Header::parse(line) {
6464
headers.push(result);
6565
continue;
6666
}

0 commit comments

Comments
 (0)