class BlockFactory extends AbstractBlockParserFactory {
        final private MacroParsing parsing;

        BlockFactory(DataHolder options) {
            super(options);
            this.parsing = new MacroParsing(new Parsing(options));
        }

        @Override
        public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {<FILL_FUNCTION_BODY>}
    }

            BasedSequence line = state.getLine();
            int currentIndent = state.getIndent();
            if (currentIndent == 0 && !(matchedBlockParser.getBlockParser().getBlock() instanceof Paragraph)) {
                final BasedSequence tryLine = line.subSequence(state.getIndex());
                Matcher matcher = parsing.MACRO_OPEN.matcher(tryLine);

                if (matcher.find()) {
                    // see if it closes on the same line, then we create a block and close it
                    BasedSequence macroName = line.subSequence(matcher.start(1), matcher.end(1));
                    BasedSequence macroOpen = tryLine.subSequence(0, matcher.end());
                    final BasedSequence afterOpen = tryLine.subSequence(matcher.end());
                    boolean oneLine = false;
                    boolean isClosedTag = false;
                    MacroClose macroClose = null;

                    if (macroOpen.endsWith("/}}")) {
                        // closed tag, if the end is blank then it is a block
                        if (afterOpen.isBlank()) {
                            // this is an open/close tag
                            oneLine = true;
                            isClosedTag = true;
                        } else {
                            return BlockStart.none();
                        }
                    } else {
                        // see if close or blank
                        if (!afterOpen.isBlank()) {
                            Matcher closeMatcher = parsing.MACRO_CLOSE_END.matcher(afterOpen);
                            if (closeMatcher.find()) {
                                if (macroName.equals(closeMatcher.group(1)) && (closeMatcher.groupCount() < 2 || closeMatcher.start(2) == -1 || (closeMatcher.group(2).length() & 1) == 1)) {
                                    // same name and not escaped
                                    oneLine = true;
                                    macroClose = new MacroClose(afterOpen.subSequence(closeMatcher.start(), closeMatcher.start() + 3),
                                            afterOpen.subSequence(closeMatcher.start(1), closeMatcher.end(1)),
                                            afterOpen.subSequence(closeMatcher.end() - 2, closeMatcher.end()));
                                    macroClose.setCharsFromContent();
                                }
                            }

                            if (!oneLine) {
                                return BlockStart.none();
                            }
                        }
                    }

                    Macro macro = new Macro(macroOpen.subSequence(0, 2), macroName, macroOpen.endSequence(isClosedTag ? 3 : 2));
                    macro.setCharsFromContent();

                    BasedSequence attributeText = macroOpen.baseSubSequence(macroName.getEndOffset(), macro.getClosingMarker().getStartOffset()).trim();
                    if (!attributeText.isEmpty()) {
                        // have some attribute text
                        macro.setAttributeText(attributeText);

                        // parse attributes
                        Matcher attributeMatcher = parsing.MACRO_ATTRIBUTE.matcher(attributeText);
                        while (attributeMatcher.find()) {
                            BasedSequence attributeName = attributeText.subSequence(attributeMatcher.start(1), attributeMatcher.end(1));
                            BasedSequence attributeSeparator = attributeMatcher.groupCount() == 1 || attributeMatcher.start(2) == -1 ? BasedSequence.NULL : attributeText.subSequence(attributeMatcher.end(1), attributeMatcher.start(2)).trim();
                            BasedSequence attributeValue = attributeMatcher.groupCount() == 1 || attributeMatcher.start(2) == -1 ? BasedSequence.NULL : attributeText.subSequence(attributeMatcher.start(2), attributeMatcher.end(2));
                            boolean isQuoted = attributeValue.length() >= 2 && (attributeValue.charAt(0) == '"' && attributeValue.endCharAt(1) == '"' || attributeValue.charAt(0) == '\'' && attributeValue.endCharAt(1) == '\'');
                            BasedSequence attributeOpen = !isQuoted ? BasedSequence.NULL : attributeValue.subSequence(0, 1);
                            BasedSequence attributeClose = !isQuoted ? BasedSequence.NULL : attributeValue.endSequence(1, 0);

                            if (isQuoted) {
                                attributeValue = attributeValue.midSequence(1, -1);
                            }

                            MacroAttribute attribute = new MacroAttribute(attributeName, attributeSeparator, attributeOpen, attributeValue, attributeClose);
                            macro.appendChild(attribute);
                        }
                    }

                    final MacroBlockParser parser = new MacroBlockParser(state.getProperties(), parsing, macroName, oneLine);
                    if (oneLine) {
                        parser.hadClose = true;
                    }

                    parser.block.appendChild(macro);
                    if (macroClose != null) parser.block.appendChild(macroClose);

                    return BlockStart.of(parser)
                            .atIndex(state.getLineEndIndex())
                            ;
                }
            }
            return BlockStart.none();
        
<methods>public non-sealed void <init>() ,public void addLine(com.vladsch.flexmark.parser.block.ParserState, com.vladsch.flexmark.util.sequence.BasedSequence) ,public boolean breakOutOnDoubleBlankLine() ,public boolean canContain(com.vladsch.flexmark.parser.block.ParserState, com.vladsch.flexmark.parser.block.BlockParser, com.vladsch.flexmark.util.ast.Block) ,public boolean canInterruptBy(com.vladsch.flexmark.parser.block.BlockParserFactory) ,public final void finalizeClosedBlock() ,public com.vladsch.flexmark.util.ast.BlockContent getBlockContent() ,public com.vladsch.flexmark.util.data.MutableDataHolder getDataHolder() ,public boolean isClosed() ,public boolean isContainer() ,public boolean isInterruptible() ,public boolean isParagraphParser() ,public boolean isPropagatingLastBlankLine(com.vladsch.flexmark.parser.block.BlockParser) ,public boolean isRawText() ,public void parseInlines(com.vladsch.flexmark.parser.InlineParser) ,public void removeBlankLines() <variables>private boolean isClosed,private com.vladsch.flexmark.util.data.MutableDataSet mutableData