1 module hunt.markdown.internal.ThematicBreakParser;
2 
3 import hunt.markdown.node.Block;
4 import hunt.markdown.node.ThematicBreak;
5 import hunt.markdown.parser.block.AbstractBlockParser;
6 import hunt.markdown.parser.block.BlockContinue;
7 import hunt.markdown.parser.block.ParserState;
8 import hunt.markdown.parser.block.BlockStart;
9 import hunt.markdown.parser.block.MatchedBlockParser;
10 import hunt.markdown.parser.block.AbstractBlockParserFactory;
11 
12 class ThematicBreakParser : AbstractBlockParser {
13 
14     private ThematicBreak block;
15 
16     this()
17     {
18         block = new ThematicBreak();
19     }
20 
21     override public Block getBlock() {
22         return block;
23     }
24 
25     public BlockContinue tryContinue(ParserState state) {
26         // a horizontal rule can never container > 1 line, so fail to match
27         return BlockContinue.none();
28     }
29 
30     public static class Factory : AbstractBlockParserFactory {
31 
32         public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
33             if (state.getIndent() >= 4) {
34                 return BlockStart.none();
35             }
36             int nextNonSpace = state.getNextNonSpaceIndex();
37             string line = state.getLine();
38             if (isThematicBreak(line, nextNonSpace)) {
39                 return BlockStart.of(new ThematicBreakParser()).atIndex(cast(int)(line.length));
40             } else {
41                 return BlockStart.none();
42             }
43         }
44     }
45 
46     // spec: A line consisting of 0-3 spaces of indentation, followed by a sequence of three or more matching -, _, or *
47     // characters, each followed optionally by any number of spaces, forms a thematic break.
48     private static bool isThematicBreak(string line, int index) {
49         int dashes = 0;
50         int underscores = 0;
51         int asterisks = 0;
52         int length =cast(int)(line.length);
53         for (int i = index; i < length; i++) {
54             switch (line[i]) {
55                 case '-':
56                     dashes++;
57                     break;
58                 case '_':
59                     underscores++;
60                     break;
61                 case '*':
62                     asterisks++;
63                     break;
64                 case ' ':
65                 case '\t':
66                     // Allowed, even between markers
67                     break;
68                 default:
69                     return false;
70             }
71         }
72 
73         return ((dashes >= 3 && underscores == 0 && asterisks == 0) ||
74                 (underscores >= 3 && dashes == 0 && asterisks == 0) ||
75                 (asterisks >= 3 && dashes == 0 && underscores == 0));
76     }
77 }