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