1 module hunt.markdown.internal.IndentedCodeBlockParser;
2 
3 import hunt.markdown.internal.util.Parsing;
4 import hunt.markdown.node.Block;
5 import hunt.markdown.node.IndentedCodeBlock;
6 import hunt.markdown.node.Paragraph;
7 import hunt.markdown.parser.block.AbstractBlockParser;
8 import hunt.markdown.parser.block.BlockContinue;
9 import hunt.markdown.parser.block.ParserState;
10 import hunt.markdown.parser.block.BlockStart;
11 import hunt.markdown.parser.block.AbstractBlockParserFactory;
12 import hunt.markdown.parser.block.MatchedBlockParser;
13 
14 import hunt.collection.ArrayList;
15 import hunt.collection.List;
16 
17 import hunt.text;
18 
19 class IndentedCodeBlockParser : AbstractBlockParser {
20 
21     private IndentedCodeBlock block;
22     private List!(string) lines;
23 
24     this()
25     {
26         block = new IndentedCodeBlock();
27         lines = new ArrayList!(string)();
28     }
29 
30     override public Block getBlock() {
31         return block;
32     }
33 
34     public BlockContinue tryContinue(ParserState state) {
35         if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT) {
36             return BlockContinue.atColumn(state.getColumn() + Parsing.CODE_BLOCK_INDENT);
37         } else if (state.isBlank()) {
38             return BlockContinue.atIndex(state.getNextNonSpaceIndex());
39         } else {
40             return BlockContinue.none();
41         }
42     }
43 
44     override public void addLine(string line) {
45         lines.add(line);
46     }
47 
48     override public void closeBlock() {
49         int lastNonBlank = lines.size() - 1;
50         while (lastNonBlank >= 0) {
51             if (!Parsing.isBlank(lines.get(lastNonBlank))) {
52                 break;
53             }
54             lastNonBlank--;
55         }
56 
57         StringBuilder sb = new StringBuilder();
58         for (int i = 0; i < lastNonBlank + 1; i++) {
59             sb.append(lines.get(i));
60             sb.append("\n");
61         }
62 
63         string literal = sb.toString();
64         block.setLiteral(literal);
65     }
66 
67     public static class Factory : AbstractBlockParserFactory {
68 
69         public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
70             // An indented code block cannot interrupt a paragraph.
71             if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT && !state.isBlank() && cast(Paragraph)state.getActiveBlockParser().getBlock() is null) {
72                 return BlockStart.of(new IndentedCodeBlockParser()).atColumn(state.getColumn() + Parsing.CODE_BLOCK_INDENT);
73             } else {
74                 return BlockStart.none();
75             }
76         }
77     }
78 }
79