Skip to content

Commit 3e16995

Browse files
author
yggverse
committed
reorganize header component
1 parent c29f1ba commit 3e16995

File tree

3 files changed

+105
-68
lines changed

3 files changed

+105
-68
lines changed

src/line/header.rs

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
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 = "###";
1+
pub mod gemtext;
2+
pub mod level;
63

7-
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) type holder
8-
pub enum Level {
9-
H1,
10-
H2,
11-
H3,
12-
}
4+
pub use gemtext::Gemtext;
5+
pub use level::Level;
136

147
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) entity holder
158
pub struct Header {
@@ -22,10 +15,25 @@ impl Header {
2215

2316
/// Parse `Self` from line string
2417
pub fn parse(line: &str) -> Option<Self> {
25-
Some(Self {
26-
level: line.to_level()?,
27-
value: line.as_value()?.to_string(),
28-
})
18+
if let Some(value) = line.as_h1_value() {
19+
return Some(Self {
20+
level: Level::H1,
21+
value: value.to_string(),
22+
});
23+
}
24+
if let Some(value) = line.as_h2_value() {
25+
return Some(Self {
26+
level: Level::H2,
27+
value: value.to_string(),
28+
});
29+
}
30+
if let Some(value) = line.as_h3_value() {
31+
return Some(Self {
32+
level: Level::H3,
33+
value: value.to_string(),
34+
});
35+
}
36+
None
2937
}
3038

3139
// Converters
@@ -35,56 +43,3 @@ impl Header {
3543
self.value.to_source(&self.level)
3644
}
3745
}
38-
39-
pub trait Gemtext {
40-
/// Get [Gemtext](https://geminiprotocol.net/docs/gemtext-specification.gmi) value for `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<&str> {
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-
}
90-
}

src/line/header/gemtext.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use super::Level;
2+
3+
pub trait Gemtext {
4+
/// Get [Gemtext](https://geminiprotocol.net/docs/gemtext-specification.gmi) value for `Self`
5+
fn as_value(&self) -> Option<&str>;
6+
/// Get parsed H1 header value for `Self`
7+
fn as_h1_value(&self) -> Option<&str>;
8+
/// Get parsed H2 header value `Self`
9+
fn as_h2_value(&self) -> Option<&str>;
10+
/// Get parsed H3 header value `Self`
11+
fn as_h3_value(&self) -> Option<&str>;
12+
/// Get parsed header value `Self` match `Level`
13+
fn as_value_match_level(&self, level: Level) -> Option<&str>;
14+
/// Convert `Self` to `Level`
15+
fn to_level(&self) -> Option<Level>;
16+
/// Convert `Self` to [Gemtext](https://geminiprotocol.net/docs/gemtext-specification.gmi) line
17+
fn to_source(&self, level: &Level) -> String;
18+
}
19+
20+
impl Gemtext for str {
21+
fn as_value(&self) -> Option<&str> {
22+
if let Some(value) = self.as_h1_value() {
23+
return Some(value);
24+
}
25+
if let Some(value) = self.as_h2_value() {
26+
return Some(value);
27+
}
28+
if let Some(value) = self.as_h3_value() {
29+
return Some(value);
30+
}
31+
None
32+
}
33+
fn as_h1_value(&self) -> Option<&str> {
34+
self.as_value_match_level(Level::H1)
35+
}
36+
fn as_h2_value(&self) -> Option<&str> {
37+
self.as_value_match_level(Level::H2)
38+
}
39+
fn as_h3_value(&self) -> Option<&str> {
40+
self.as_value_match_level(Level::H3)
41+
}
42+
fn as_value_match_level(&self, level: Level) -> Option<&str> {
43+
if let Some(value) = self.strip_prefix(level.as_tag()) {
44+
if value.trim_start().starts_with(Level::H1.as_tag()) {
45+
return None;
46+
}
47+
return Some(value.trim());
48+
}
49+
None
50+
}
51+
fn to_level(&self) -> Option<Level> {
52+
if self.as_h1_value().is_some() {
53+
return Some(Level::H1);
54+
}
55+
if self.as_h2_value().is_some() {
56+
return Some(Level::H2);
57+
}
58+
if self.as_h3_value().is_some() {
59+
return Some(Level::H3);
60+
}
61+
None
62+
}
63+
fn to_source(&self, level: &Level) -> String {
64+
format!("{} {}", level.as_tag(), self.trim())
65+
}
66+
}

src/line/header/level.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) type holder
2+
pub enum Level {
3+
H1,
4+
H2,
5+
H3,
6+
}
7+
8+
impl Level {
9+
pub fn as_tag(&self) -> &str {
10+
match self {
11+
Level::H1 => "#",
12+
Level::H2 => "##",
13+
Level::H3 => "###",
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)