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 = "###" ;
2
6
3
7
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) type holder
4
8
pub enum Level {
@@ -9,32 +13,78 @@ pub enum Level {
9
13
10
14
/// [Header](https://geminiprotocol.net/docs/gemtext-specification.gmi#heading-lines) entity holder
11
15
pub struct Header {
12
- pub value : String ,
13
16
pub level : Level ,
17
+ pub value : String ,
14
18
}
15
19
16
20
impl Header {
17
21
// Constructors
18
22
19
23
/// 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 > {
30
25
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 ( ) ,
38
28
} )
39
29
}
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
+ }
40
90
}
0 commit comments