// Root,                           --- Done
        // Paragraph,                      --- Done
        // Header,// #(1-6)、===、---      --- Done
        // HorizontalRule,// ---、***
        // List, // +、-、*、number.       --- Done
        // Code,  // Four spaces or \t
        // Quote, // >
        // ListItemBuilder,
        // Table, // 表 | 1 | 2 |
        // LinkReference, // [name](url)

        internal static MarkdownBlock ParseBlock(string markdownText, int start, int end, out int actualEnd)
        {
            actualEnd = start;
            MarkdownBlock block        = null;
            char          nonSpaceChar = GetNonSpaceChar(markdownText, start, end, out int nonSpacePos);

            if (nonSpaceChar == '#' && nonSpacePos == start)
            {
                block = HeaderBlock.Parse(markdownText, start, end, out actualEnd);
            }

            if (block == null && (nonSpaceChar == '*' || nonSpaceChar == '-' || nonSpaceChar == '_'))
            {
                block = HorizontalRuleBlock.Parse(markdownText, start, end, out actualEnd);
            }

            if (block == null && (nonSpaceChar == '*' || nonSpaceChar == '+' || nonSpaceChar == '-' || (nonSpaceChar >= '0' && nonSpaceChar <= '9')))
            {
                block = ListElement.Parse(markdownText, start, end, out actualEnd);
            }

            if (block == null)
            {
                block = ParagraphBlock.Parse(markdownText, start, end, out actualEnd);
            }

            return(block);
        }
Exemple #2
0
        public async Task RunAsync(string script)
        {
            MarkdownDocument document = new MarkdownDocument();

            document.Parse(script);

            Console.WriteLine($"Parsed {document.Blocks.Count} blocks");
            cursor = new MarkdownCursor(document.Blocks);

            MarkdownBlock block = cursor.Current;

            while (block != null)
            {
                switch (block)
                {
                case CodeBlock cb:
                    HandleCodeBlock(cb); break;

                default:
                    HandleTextBlock(block);
                    cursor.MoveNext();
                    break;
                }

                block = cursor.Current;
            }

            Console.WriteLine("All blocks processed");
        }
        /// <summary>
        /// Called to render a block element.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="currentBlocks"></param>
        private void RendnerBlock(MarkdownBlock element, BlockCollection currentBlocks)
        {
            switch (element.Type)
            {
            case MarkdownBlockType.Paragraph:
                RenderPargraph((ParagraphBlock)element, currentBlocks);
                break;

            case MarkdownBlockType.Quote:
                RenderQuote((QuoteBlock)element, currentBlocks);
                break;

            case MarkdownBlockType.Code:
                RenderCode((CodeBlock)element, currentBlocks);
                break;

            case MarkdownBlockType.Header:
                RenderHeader((HeaderBlock)element, currentBlocks);
                break;

            case MarkdownBlockType.ListElement:
                RenderListElement((ListElementBlock)element, currentBlocks);
                break;

            case MarkdownBlockType.HorizontalRule:
                RenderHorizontalRule((HorizontalRuleBlock)element, currentBlocks);
                break;

            case MarkdownBlockType.LineBreak:
                RenderLineBreak((LineBreakBlock)element, currentBlocks);
                break;
            }
        }
Exemple #4
0
        /// <summary>
        /// Called to render a block element.
        /// </summary>
        private void RenderBlock(MarkdownBlock element, UIElementCollection blockUIElementCollection, RenderContext context)
        {
            switch (element.Type)
            {
            case MarkdownBlockType.Paragraph:
                RenderParagraph((ParagraphBlock)element, blockUIElementCollection, context);
                break;

            case MarkdownBlockType.Quote:
                RenderQuote((QuoteBlock)element, blockUIElementCollection, context);
                break;

            case MarkdownBlockType.Code:
                RenderCode((CodeBlock)element, blockUIElementCollection, context);
                break;

            case MarkdownBlockType.Header:
                RenderHeader((HeaderBlock)element, blockUIElementCollection, context);
                break;

            case MarkdownBlockType.List:
                RenderListElement((ListBlock)element, blockUIElementCollection, context);
                break;

            case MarkdownBlockType.HorizontalRule:
                RenderHorizontalRule(blockUIElementCollection, context);
                break;

            case MarkdownBlockType.Table:
                RenderTable((TableBlock)element, blockUIElementCollection, context);
                break;
            }
        }
        /// <summary>
        /// Called to render a block element.
        /// </summary>
        protected void RenderBlock(MarkdownBlock element, IRenderContext context)
        {
            {
                switch (element.Type)
                {
                case MarkdownBlockType.Paragraph:
                    RenderParagraph((ParagraphBlock)element, context);
                    break;

                case MarkdownBlockType.Quote:
                    RenderQuote((QuoteBlock)element, context);
                    break;

                case MarkdownBlockType.Code:
                    RenderCode((CodeBlock)element, context);
                    break;

                case MarkdownBlockType.Header:
                    RenderHeader((HeaderBlock)element, context);
                    break;

                case MarkdownBlockType.List:
                    RenderListElement((ListBlock)element, context);
                    break;

                case MarkdownBlockType.HorizontalRule:
                    RenderHorizontalRule(context);
                    break;

                case MarkdownBlockType.Table:
                    RenderTable((TableBlock)element, context);
                    break;
                }
            }
        }
 public static string ToHtml(this MarkdownBlock block)
 {
     if (block is ParagraphBlock paragraph)
     {
         return($"<p>{paragraph.Inlines.ToHtml().TrimStart()}</p>");
     }
     if (block is CodeBlock code)
     {
         return($"<code class=\"language-{code.CodeLanguage}\">{code.Text}</code>");
     }
     if (block is HeaderBlock header)
     {
         return($"<h{header.HeaderLevel}>{header.Inlines.ToHtml()}</h{header.HeaderLevel}>");
     }
     if (block is HorizontalRuleBlock)
     {
         return($"<hr>");
     }
     if (block is ListBlock list)
     {
         StringBuilder sb = new StringBuilder();
         sb.AppendLine("<li>");
         foreach (ListItemBlock item in list.Items)
         {
             foreach (MarkdownBlock itemBlock in item.Blocks)
             {
                 sb.AppendLine(itemBlock.ToHtml());
             }
         }
         sb.AppendLine("</li>");
         return(sb.ToString());
     }
     return(block.ToString());
 }
Exemple #7
0
 public static Block CreateBlock(MarkdownBlock block)
 {
     return(block.Type switch
     {
         MarkdownBlockType.Header => CreateHeader((HeaderBlock)block),
         MarkdownBlockType.Paragraph => CreateParagraph((ParagraphBlock)block),
         MarkdownBlockType.List => CreateList((ListBlock)block),
         _ => new Paragraph()
     });
Exemple #8
0
        private async Task <string> GetBlockAsync(MarkdownBlock block)
        {
            switch (block.Type)
            {
            case MarkdownBlockType.Header:
                var header = (HeaderBlock)block;
                return($"<h{header.HeaderLevel}>{GetMarkdownInlines(header.Inlines)}</h{header.HeaderLevel}>");

            case MarkdownBlockType.HorizontalRule:
                return($"<hr/>");

            case MarkdownBlockType.Paragraph:
                var paragraphBlock = (ParagraphBlock)block;
                return($"<p>{GetMarkdownInlines(paragraphBlock.Inlines)}</p>");

            case MarkdownBlockType.Code:
                var codeBlock = (CodeBlock)block;
                return($"<div class='md-code'>{_codeTextService.GetCodeText(codeBlock.Text, codeBlock.CodeLanguage)}</div>");

            case MarkdownBlockType.List:
                var list       = (ListBlock)block;
                var listString = $"<div class='md-list'>";
                foreach (var item in list.Items)
                {
                    listString += $"<div class='md-list-row'>" +
                                  $"<div class='md-list-point'>{GetPointImg(list.Style)}</div>" +
                                  $"<div class='md-list-item'>";
                    foreach (var itemBlock in item.Blocks)
                    {
                        listString += $"<div>{await GetBlockAsync(itemBlock) }</div>";
                    }
                    listString += $"</div></div>";
                }
                listString += $"</div>";
                listNum     = 1;
                return(listString);

            case MarkdownBlockType.LinkReference:
                var linkBlock = (LinkReferenceBlock)block;
                return($"<a href='{linkBlock.Tooltip}'>).Text){linkBlock.Url}</a>");

            case MarkdownBlockType.Quote:
                var quoteBlock = (QuoteBlock)block;
                var result     = "<div class='md-list-row'><div class='md-quote-img'> </div><div class='md-quote-text'>";
                foreach (var itemBlock in quoteBlock.Blocks)
                {
                    result += $"{await GetBlockAsync(itemBlock)}";
                }
                result += $"</div></div>";
                return(result);

            default:
                return(GetCustomBlock(block.ToString()));
            }
        }
 private static ValueTask HandleDescription(ProjectInfo info, MarkdownBlock block)
 {
     if (block is ParagraphBlock paragraph)
     {
         info.Description = paragraph.ReadAllInline().Trim();
     }
     if (block is CodeBlock code)
     {
         info.Description = code.Text;
     }
     return(default);
Exemple #10
0
        private static async Task <IEnumerable <IApiSlideBlock> > RenderBlock(MarkdownBlock mb, SlideRenderContext context)
        {
            var renderedMarkdown = mb.RenderMarkdown(context.CourseId, context.Slide, context.BaseUrl);
            var parsedBlocks     = ParseBlocksFromMarkdown(renderedMarkdown);

            if (mb.Hide)
            {
                parsedBlocks.ForEach(b => b.Hide = true);
            }
            return(parsedBlocks);
        }
Exemple #11
0
        private void MoveToPreviousCodeBlock()
        {
            MarkdownBlock block = cursor.Current;

            do
            {
                cursor.MovePrevious();
                block = cursor.Current;
            } while (block != null && !(block is CodeBlock));

            if (block == null)
            {
                cursor.MoveNext();                //If we hit the beginning, then start from the first one
            }
        }
Exemple #12
0
        internal static List <MarkdownBlock> ParseBlocks(string markdownText, int start, int end)
        {
            var blocks   = new List <MarkdownBlock>();
            int startPos = start;

            while (startPos < end)
            {
                MarkdownBlock newBlock = ParseBlocksHelper.ParseBlock(markdownText, startPos, end, out int endPos);
                if (newBlock != null)
                {
                    blocks.Add(newBlock);
                }
                startPos = endPos + 1;
            }
            return(blocks);
        }
Exemple #13
0
            private void RenderBlcok(MarkdownBlock block, UIElementCollection blockUIElementCollection)
            {
                switch (block.Type)
                {
                case MarkdownBlockType.Paragraph:
                    RenderParagraph((ParagraphBlock)block, blockUIElementCollection);
                    break;

                case MarkdownBlockType.Header:
                    RenderHeader((HeaderBlock)block, blockUIElementCollection);
                    break;

                case MarkdownBlockType.ListElement:
                    RenderListElement((ListElement)block, blockUIElementCollection);
                    break;
                }
            }
        public static Block CreateBlock(MarkdownBlock block)
        {
            switch (block.Type)
            {
            case MarkdownBlockType.Header:
                return(CreateHeader(block as HeaderBlock));

            case MarkdownBlockType.Paragraph:
                return(CreateParagraph(block as ParagraphBlock));

            case MarkdownBlockType.List:
                return(CreateList(block as ListBlock));

            default:
                return(new Paragraph());
            }
        }
        private void AnalyzeParagraph(MarkdownBlock element, RequirementSpecification data)
        {
            var item = data.Requirements.Last();

            switch (status)
            {
            case UsdmScope.UpperRequiremetReason:
                item.Reason += element.ToString() ?? string.Empty;
                break;

            case UsdmScope.UpperRequiremetDescription:
                item.Description += element.ToString() ?? string.Empty;
                break;

            case UsdmScope.LowerRequiremetReason:
                item.Requirements.Last().Reason += element.ToString() ?? string.Empty;
                break;

            case UsdmScope.LowerRequiremetDescription:
                item.Requirements.Last().Description += element.ToString() ?? string.Empty;
                break;

            case UsdmScope.Specification:
                var rawString = element.ToString();
                if (rawString != null)
                {
                    item.Requirements.Last()
                    .SpecificationGroups.Add(
                        new SpecificationGroup
                    {
                        Category = ParseUtility.ExtractGroupCategory(rawString)
                    }
                        );
                }
                break;

            default:
                Console.WriteLine($"Type: {element.Type}");
                Console.WriteLine(element.ToString());
                break;
            }
        }
        private void AnalyzeList(MarkdownBlock element, RequirementSpecification data)
        {
            switch (status)
            {
            case UsdmScope.UpperRequiremetReason:
                data.Requirements.Last().Reason += "\n" + element.ToString() ?? string.Empty;
                break;

            case UsdmScope.UpperRequiremetDescription:
                data.Requirements.Last().Description += "\n" + element.ToString() ?? string.Empty;
                break;

            case UsdmScope.LowerRequiremetReason:
                data.Requirements.Last().Requirements.Last().Reason += "\n" + element.ToString() ?? string.Empty;
                break;

            case UsdmScope.LowerRequiremetDescription:
                data.Requirements.Last().Requirements.Last().Description += "\n" + element.ToString() ?? string.Empty;
                break;

            case UsdmScope.Specification:
                var listBlock = element as ListBlock;
                if (listBlock != null)
                {
                    data.Requirements.Last()
                    .Requirements.Last()
                    .SpecificationGroups.Last()
                    .Specifications.AddRange(
                        ParseUtility.DecomposeSpecification(listBlock)
                        );
                }
                break;

            default:
                Console.WriteLine($"Type: {element.Type}");
                Console.WriteLine(element.ToString());
                break;
            }
        }
Exemple #17
0
        private void HandleTextBlock(MarkdownBlock block)
        {
            var oldColor = Console.ForegroundColor;

            if (block is HeaderBlock header)
            {
                if (header.HeaderLevel == 1)
                {
                    Console.ForegroundColor = ConsoleColor.Cyan;
                }
                else if (header.HeaderLevel == 2)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Magenta;
                }
            }

            Console.WriteLine(block.ToString());

            Console.ForegroundColor = oldColor;
        }
Exemple #18
0
        /// <summary>
        /// Parses a markdown document.
        /// </summary>
        /// <param name="markdown"> The markdown text. </param>
        /// <param name="start"> The position to start parsing. </param>
        /// <param name="end"> The position to stop parsing. </param>
        /// <param name="quoteDepth"> The current nesting level for block quoting. </param>
        /// <param name="actualEnd"> Set to the position at which parsing ended.  This can be
        /// different from <paramref name="end"/> when the parser is being called recursively.
        /// </param>
        /// <returns> A list of parsed blocks. </returns>
        internal static List <MarkdownBlock> Parse(string markdown, bool inlineOnly, int start, int end, int quoteDepth, out int actualEnd)
        {
            // We need to parse out the list of blocks.
            // Some blocks need to start on a new paragraph (code, lists and tables) while other
            // blocks can start on any line (headers, horizontal rules and quotes).
            // Text that is outside of any other block becomes a paragraph.
            var blocks        = new List <MarkdownBlock>();
            var startOfLine   = start;
            var paragraphText = new StringBuilder();

            // These are needed to parse underline-style header blocks.
            var previousRealtStartOfLine = start;
            var previousStartOfLine      = start;
            var previousEndOfLine        = start;
            var skip = false;

            // Go line by line.
            while (startOfLine < end)
            {
                // Find the first non-whitespace character.
                var nonSpacePos             = startOfLine;
                var nonSpaceChar            = '\0';
                var realStartOfLine         = startOfLine; // i.e. including quotes.
                var expectedQuotesRemaining = quoteDepth;
                while (true)
                {
                    while (nonSpacePos < end)
                    {
                        var c = markdown[nonSpacePos];
                        if (c == '\r' || c == '\n')
                        {
                            // The line is either entirely whitespace, or is empty.
                            break;
                        }

                        if (c != ' ' && c != '\t')
                        {
                            // The line has content.
                            nonSpaceChar = c;
                            break;
                        }

                        nonSpacePos++;
                    }

                    // When parsing blocks in a blockquote context, we need to count the number of
                    // quote characters ('>').  If there are less than expected AND this is the
                    // start of a new paragraph, then stop parsing.
                    if (expectedQuotesRemaining == 0)
                    {
                        break;
                    }

                    if (nonSpaceChar == '>')
                    {
                        // Expected block quote characters should be ignored.
                        expectedQuotesRemaining--;
                        nonSpacePos++;
                        nonSpaceChar = '\0';
                        startOfLine  = nonSpacePos;

                        // Ignore the first space after the quote character, if there is one.
                        if (!(startOfLine < end && markdown[startOfLine] == ' '))
                        {
                            skip = true;
                        }
                    }
                    else
                    {
                        var    lastIndentation = 0;
                        string lastline        = null;

                        // Determines how many Quote levels were in the last line.
                        if (realStartOfLine > 0)
                        {
                            lastline        = markdown.Substring(previousRealtStartOfLine, previousEndOfLine - previousRealtStartOfLine);
                            lastIndentation = lastline.Count(c => c == '>');
                        }

                        var currentEndOfLine   = Common.FindNextSingleNewLine(markdown, nonSpacePos, end, out _);
                        var currentline        = markdown.Substring(realStartOfLine, currentEndOfLine - realStartOfLine);
                        var currentIndentation = currentline.Count(c => c == '>');
                        var firstChar          = markdown[realStartOfLine];

                        // This is a quote that doesn't start with a Quote marker, but carries on from the last line.
                        if (lastIndentation == 1)
                        {
                            if (nonSpaceChar != '\0' && firstChar != '>')
                            {
                                break;
                            }
                        }

                        // Collapse down a level of quotes if the current indentation is greater than the last indentation.
                        // Only if the last indentation is greater than 1, and the current indentation is greater than 0
                        if (lastIndentation > 1 && currentIndentation > 0 && currentIndentation < lastIndentation)
                        {
                            break;
                        }

                        // This must be the end of the blockquote.  End the current paragraph, if any.
                        actualEnd = realStartOfLine;

                        if (paragraphText.Length > 0)
                        {
                            blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                        }

                        return(blocks);
                    }
                }

                // Find the end of the current line.
                var endOfLine = Common.FindNextSingleNewLine(markdown, nonSpacePos, end, out var startOfNextLine);

                if (nonSpaceChar == '\0')
                {
                    // The line is empty or nothing but whitespace.

                    // End the current paragraph.
                    if (paragraphText.Length > 0)
                    {
                        blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                        paragraphText.Clear();
                    }
                }
                else
                {
                    // This is a header if the line starts with a hash character,
                    // or if the line starts with '-' or a '=' character and has no other characters.
                    // Or a quote if the line starts with a greater than character (optionally preceded by whitespace).
                    // Or a horizontal rule if the line contains nothing but 3 '*', '-' or '_' characters (with optional whitespace).
                    MarkdownBlock newBlockElement = null;

                    if (newBlockElement == null)
                    {
                        // Some block elements must start on a new paragraph (tables, lists and code).
                        var endOfBlock = startOfNextLine;

                        if (newBlockElement == null && nonSpaceChar == '`' && !inlineOnly)
                        {
                            newBlockElement = CodeBlock.Parse(markdown, realStartOfLine, end, quoteDepth, out endOfBlock);
                        }

                        // This check needs to go after the code block check.
                        if (newBlockElement == null && nonSpaceChar == '>' && !inlineOnly && nonSpacePos + 1 < end && markdown[nonSpacePos + 1] == ' ')
                        {
                            newBlockElement = QuoteBlock.Parse(markdown, realStartOfLine, startOfNextLine, quoteDepth, out endOfBlock);
                        }

                        if (newBlockElement != null)
                        {
                            startOfNextLine = endOfBlock;
                        }
                    }

                    // Block elements start new paragraphs.
                    if (newBlockElement == null)
                    {
                        // The line contains paragraph text.
                        if (paragraphText.Length > 0)
                        {
                            paragraphText.Append("\r\n");
                        }

                        // Add the last paragraph if we are at the end of the input text.
                        if (startOfNextLine >= end)
                        {
                            if (paragraphText.Length == 0)
                            {
                                // Optimize for single line paragraphs.
                                blocks.Add(ParagraphBlock.Parse(markdown.Substring(startOfLine, endOfLine - startOfLine)));
                            }
                            else
                            {
                                // Slow path.
                                paragraphText.Append(markdown.Substring(startOfLine, endOfLine - startOfLine));
                                blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                            }
                        }
                        else
                        {
                            paragraphText.Append(markdown.Substring(startOfLine, endOfLine - startOfLine));
                        }
                    }
                    else
                    {
                        // The line contained a block.  End the current paragraph, if any.
                        if (paragraphText.Length > 0)
                        {
                            blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                            paragraphText.Clear();
                        }

                        blocks.Add(newBlockElement);
                    }
                }

                // Repeat.
                previousRealtStartOfLine = realStartOfLine;
                previousStartOfLine      = startOfLine;
                previousEndOfLine        = endOfLine;
                startOfLine = startOfNextLine;
            }

            actualEnd = startOfLine;
            return(blocks);
        }
Exemple #19
0
        public static Element Block2Element(this MarkdownBlock block)
        {
            switch (block.Type)
            {
            case MarkdownBlockType.Root:
                var doc = block as MarkdownDocument;
                var md  = new MarkDown();
                md.Title = "";
                md.RootElements.AddRange(doc.Blocks.Select(b => b.Block2Element()));
                return(md);

            case MarkdownBlockType.Header:
                var headerBlock = block as HeaderBlock;
                var section     = new Section();
                var titleLine   = new Seq();
                titleLine.Values.AddRange(headerBlock.Inlines.Select(l => l.Inline2Element()));
                section.Title = titleLine;
                section.Level = headerBlock.HeaderLevel;
                return(section);

            case MarkdownBlockType.Code:
                var code = block as CodeBlock;

                var lines = code.Lines.Select(l => new Line()
                {
                    Value = l
                });
                var c = new Code();
                c.Lines.AddRange(lines);
                c.CodeKind = CodeKind.Block;
                return(c);

            case MarkdownBlockType.Quote:
                var quote = block as QuoteBlock;
                var bq    = new Blockquote();
                bq.Values.AddRange(quote.Blocks.Select(b => b.Block2Element()));
                return(bq);

            case MarkdownBlockType.Paragraph:
                var paraBlock = block as ParagraphBlock;
                var paragraph = new Paragraph();
                paragraph.Values.AddRange(paraBlock.Inlines.Select(l => l.Inline2Element()));
                return(paragraph);

            case MarkdownBlockType.Table:
                var tableBlock = block as TableBlock;
                var table      = new Table();

                int ri = 0;
                foreach (var rowBlock in tableBlock.Rows)
                {
                    var row = new Row();
                    var cd  = 0;
                    if (ri == 0)
                    {
                        row.RowKind = tableBlock.HasHeaderRow ? RowKind.Head : RowKind.Body;
                        ri++;
                    }
                    else
                    {
                        row.RowKind = RowKind.Body;
                    }

                    foreach (var cellBlock in rowBlock.Cells)
                    {
                        var column    = tableBlock.ColumnDefinitions[cd++];
                        var cell      = new Cell();
                        var blockLine = new Seq();
                        blockLine.Values.AddRange(cellBlock.Inlines.Select(i => i.Inline2Element()));
                        cell.Value = blockLine;
                        cell.Align = column.Alignment.ColumnAlignToString();

                        cell.CellKind = row.RowKind == RowKind.Head ? CellKind.Head : CellKind.Cell;
                        row.Cells.Add(cell);
                    }

                    table.Rows.Add(row);
                }
                return(table);

            case MarkdownBlockType.LinkReference:
                var link      = block as LinkReferenceBlock;
                var hyperlink = new HyperLink();
                hyperlink.Text = new Text {
                    Value = link.ToString()
                };
                hyperlink.Url = new Uri(link.Url);
                return(hyperlink);

            case MarkdownBlockType.HorizontalRule:
                var hr = block as HorizontalRuleBlock;
                return(new Rule {
                    Value = hr.ToString()
                });

            case MarkdownBlockType.List:
                var listBlock = block as ListBlock;
                var list      = new List();
                list.ListKind = listBlock.Style == ListStyle.Numbered ? ListKind.Order : ListKind.UnOrder;

                foreach (var listItemBlock in listBlock.Items)
                {
                    foreach (var b in listItemBlock.Blocks)
                    {
                        var e = b.Block2Element();
                        list.Items.Add(e);
                    }
                }
                return(list);

            default:
                return(null);
            }
        }
Exemple #20
0
 private bool IsVersionSectionHeader(MarkdownBlock block, string version)
 => block is HeaderBlock header &&
Exemple #21
0
        /// <summary>
        /// Parses a markdown document.
        /// </summary>
        /// <param name="markdown"> The markdown text. </param>
        /// <param name="start"> The position to start parsing. </param>
        /// <param name="end"> The position to stop parsing. </param>
        /// <param name="quoteDepth"> The current nesting level for block quoting. </param>
        /// <param name="actualEnd"> Set to the position at which parsing ended.  This can be
        /// different from <paramref name="end"/> when the parser is being called recursively.
        /// </param>
        /// <returns> A list of parsed blocks. </returns>
        internal static List <MarkdownBlock> Parse(string markdown, int start, int end, int quoteDepth, out int actualEnd)
        {
            // We need to parse out the list of blocks.
            // Some blocks need to start on a new paragraph (code, lists and tables) while other
            // blocks can start on any line (headers, horizontal rules and quotes).
            // Text that is outside of any other block becomes a paragraph.
            var  blocks                 = new List <MarkdownBlock>();
            int  startOfLine            = start;
            bool lineStartsNewParagraph = true;
            var  paragraphText          = new StringBuilder();

            // These are needed to parse underline-style header blocks.
            int previousRealtStartOfLine = start;
            int previousStartOfLine      = start;
            int previousEndOfLine        = start;

            // Go line by line.
            while (startOfLine < end)
            {
                // Find the first non-whitespace character.
                int  nonSpacePos             = startOfLine;
                char nonSpaceChar            = '\0';
                int  realStartOfLine         = startOfLine; // i.e. including quotes.
                int  expectedQuotesRemaining = quoteDepth;
                while (true)
                {
                    while (nonSpacePos < end)
                    {
                        char c = markdown[nonSpacePos];
                        if (c == '\r' || c == '\n')
                        {
                            // The line is either entirely whitespace, or is empty.
                            break;
                        }

                        if (c != ' ' && c != '\t')
                        {
                            // The line has content.
                            nonSpaceChar = c;
                            break;
                        }

                        nonSpacePos++;
                    }

                    // When parsing blocks in a blockquote context, we need to count the number of
                    // quote characters ('>').  If there are less than expected AND this is the
                    // start of a new paragraph, then stop parsing.
                    if (expectedQuotesRemaining == 0)
                    {
                        break;
                    }

                    if (nonSpaceChar == '>')
                    {
                        // Expected block quote characters should be ignored.
                        expectedQuotesRemaining--;
                        nonSpacePos++;
                        nonSpaceChar = '\0';
                        startOfLine  = nonSpacePos;

                        // Ignore the first space after the quote character, if there is one.
                        if (startOfLine < end && markdown[startOfLine] == ' ')
                        {
                            startOfLine++;
                            nonSpacePos++;
                        }
                    }
                    else
                    {
                        int    lastIndentation = 0;
                        string lastline        = null;

                        // Determines how many Quote levels were in the last line.
                        if (realStartOfLine > 0)
                        {
                            lastline        = markdown.Substring(previousRealtStartOfLine, previousEndOfLine - previousRealtStartOfLine);
                            lastIndentation = lastline.Count(c => c == '>');
                        }

                        var currentEndOfLine   = Common.FindNextSingleNewLine(markdown, nonSpacePos, end, out _);
                        var currentline        = markdown.Substring(realStartOfLine, currentEndOfLine - realStartOfLine);
                        var currentIndentation = currentline.Count(c => c == '>');
                        var firstChar          = markdown[realStartOfLine];

                        // This is a quote that doesn't start with a Quote marker, but carries on from the last line.
                        if (lastIndentation == 1)
                        {
                            if (nonSpaceChar != '\0' && firstChar != '>')
                            {
                                break;
                            }
                        }

                        // Collapse down a level of quotes if the current indentation is greater than the last indentation.
                        // Only if the last indentation is greater than 1, and the current indentation is greater than 0
                        if (lastIndentation > 1 && currentIndentation > 0 && currentIndentation < lastIndentation)
                        {
                            break;
                        }

                        // This must be the end of the blockquote.  End the current paragraph, if any.
                        actualEnd = realStartOfLine;

                        if (paragraphText.Length > 0)
                        {
                            blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                        }

                        return(blocks);
                    }
                }

                // Find the end of the current line.
                int startOfNextLine;
                int endOfLine = Common.FindNextSingleNewLine(markdown, nonSpacePos, end, out startOfNextLine);

                if (nonSpaceChar == '\0')
                {
                    // The line is empty or nothing but whitespace.
                    lineStartsNewParagraph = true;

                    // End the current paragraph.
                    if (paragraphText.Length > 0)
                    {
                        blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                        paragraphText.Clear();
                    }
                }
                else
                {
                    // This is a header if the line starts with a hash character,
                    // or if the line starts with '-' or a '=' character and has no other characters.
                    // Or a quote if the line starts with a greater than character (optionally preceded by whitespace).
                    // Or a horizontal rule if the line contains nothing but 3 '*', '-' or '_' characters (with optional whitespace).
                    MarkdownBlock newBlockElement = null;
                    if (nonSpaceChar == '#' && nonSpacePos == startOfLine)
                    {
                        // Hash-prefixed header.
                        newBlockElement = HeaderBlock.ParseHashPrefixedHeader(markdown, startOfLine, endOfLine);
                    }
                    else if ((nonSpaceChar == '-' || nonSpaceChar == '=') && nonSpacePos == startOfLine && paragraphText.Length > 0)
                    {
                        // Underline style header. These are weird because you don't know you've
                        // got one until you've gone past it.
                        // Note: we intentionally deviate from reddit here in that we only
                        // recognize this type of header if the previous line is part of a
                        // paragraph.  For example if you have this, the header at the bottom is
                        // ignored:
                        //   a|b
                        //   -|-
                        //   1|2
                        //   ===
                        newBlockElement = HeaderBlock.ParseUnderlineStyleHeader(markdown, previousStartOfLine, previousEndOfLine, startOfLine, endOfLine);

                        if (newBlockElement != null)
                        {
                            // We're going to have to remove the header text from the pending
                            // paragraph by prematurely ending the current paragraph.
                            // We already made sure that there is a paragraph in progress.
                            paragraphText.Length = paragraphText.Length - (previousEndOfLine - previousStartOfLine);
                        }
                    }

                    // These characters overlap with the underline-style header - this check should go after that one.
                    if (newBlockElement == null && (nonSpaceChar == '*' || nonSpaceChar == '-' || nonSpaceChar == '_'))
                    {
                        newBlockElement = HorizontalRuleBlock.Parse(markdown, startOfLine, endOfLine);
                    }

                    if (newBlockElement == null && lineStartsNewParagraph)
                    {
                        // Some block elements must start on a new paragraph (tables, lists and code).
                        int endOfBlock = startOfNextLine;
                        if (nonSpaceChar == '*' || nonSpaceChar == '+' || nonSpaceChar == '-' || (nonSpaceChar >= '0' && nonSpaceChar <= '9'))
                        {
                            newBlockElement = ListBlock.Parse(markdown, realStartOfLine, end, quoteDepth, out endOfBlock);
                        }

                        if (newBlockElement == null && (nonSpacePos > startOfLine || nonSpaceChar == '`'))
                        {
                            newBlockElement = CodeBlock.Parse(markdown, realStartOfLine, end, quoteDepth, out endOfBlock);
                        }

                        if (newBlockElement == null)
                        {
                            newBlockElement = TableBlock.Parse(markdown, realStartOfLine, endOfLine, end, quoteDepth, out endOfBlock);
                        }

                        if (newBlockElement != null)
                        {
                            startOfNextLine = endOfBlock;
                        }
                    }

                    // This check needs to go after the code block check.
                    if (newBlockElement == null && nonSpaceChar == '>')
                    {
                        newBlockElement = QuoteBlock.Parse(markdown, realStartOfLine, end, quoteDepth, out startOfNextLine);
                    }

                    // This check needs to go after the code block check.
                    if (newBlockElement == null && nonSpaceChar == '[')
                    {
                        newBlockElement = LinkReferenceBlock.Parse(markdown, startOfLine, endOfLine);
                    }

                    // Block elements start new paragraphs.
                    lineStartsNewParagraph = newBlockElement != null;

                    if (newBlockElement == null)
                    {
                        // The line contains paragraph text.
                        if (paragraphText.Length > 0)
                        {
                            // If the previous two characters were both spaces, then append a line break.
                            if (paragraphText.Length > 2 && paragraphText[paragraphText.Length - 1] == ' ' && paragraphText[paragraphText.Length - 2] == ' ')
                            {
                                // Replace the two spaces with a line break.
                                paragraphText[paragraphText.Length - 2] = '\r';
                                paragraphText[paragraphText.Length - 1] = '\n';
                            }
                            else
                            {
                                paragraphText.Append(" ");
                            }
                        }

                        // Add the last paragraph if we are at the end of the input text.
                        if (startOfNextLine >= end)
                        {
                            if (paragraphText.Length == 0)
                            {
                                // Optimize for single line paragraphs.
                                blocks.Add(ParagraphBlock.Parse(markdown.Substring(startOfLine, endOfLine - startOfLine)));
                            }
                            else
                            {
                                // Slow path.
                                paragraphText.Append(markdown.Substring(startOfLine, endOfLine - startOfLine));
                                blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                            }
                        }
                        else
                        {
                            paragraphText.Append(markdown.Substring(startOfLine, endOfLine - startOfLine));
                        }
                    }
                    else
                    {
                        // The line contained a block.  End the current paragraph, if any.
                        if (paragraphText.Length > 0)
                        {
                            blocks.Add(ParagraphBlock.Parse(paragraphText.ToString()));
                            paragraphText.Clear();
                        }

                        blocks.Add(newBlockElement);
                    }
                }

                // Repeat.
                previousRealtStartOfLine = realStartOfLine;
                previousStartOfLine      = startOfLine;
                previousEndOfLine        = endOfLine;
                startOfLine = startOfNextLine;
            }

            actualEnd = startOfLine;
            return(blocks);
        }
Exemple #22
0
 private string RenderBlock(MarkdownBlock block)
 => _blockRenderer.Render(block, RenderBlocks);
 /// <summary>
 /// Renders an element.
 /// </summary>
 /// <param name="element"> The parsed block element to render. </param>
 /// <param name="context"> Persistent state. </param>
 protected virtual void RenderOther(MarkdownBlock element, IRenderContext context)
 {
 }
 /// <summary>
 /// Recurses markdown blocks.
 /// </summary>
 /// <param name="block">The parent block.</param>
 /// <param name="candidate">The <see cref="FileDataParse"/> to parse to.</param>
 /// <param name="words">The <see cref="StringBuilder"/> for the words list.</param>
 /// <param name="titles">The title cache.</param>
 private FileDataParse RecurseBlock(
     MarkdownBlock block,
     FileDataParse candidate,
     StringBuilder words,
     List <(int level, string title)> titles)
Exemple #25
0
 private static bool IsCommentParagraph(MarkdownBlock block)
 {
     return(block is ParagraphBlock p &&
            p.Inlines.Count == 1 &&
            p.Inlines[0].Type == MarkdownInlineType.Comment);
 }
Exemple #26
0
        public static ArticleData Parse(string article, ArticleHeadInfo articleHeadInfo, bool debug = false)
        {
            string      content = File.ReadAllText(article);
            ArticleData ad      = new ArticleData(articleHeadInfo);

            MarkdownDocument document = new MarkdownDocument();

            document.Parse(content);

            List <MarkdownBlock> elements        = new List <MarkdownBlock>();
            List <ChapterData>   chapters        = new List <ChapterData>();
            ChapterData          chapter         = new ChapterData();
            List <MarkdownBlock> chapterElements = new List <MarkdownBlock>();

            void AddChapter()
            {
                if (chapterElements.Count > 0)
                {
                    chapter.Elements = chapterElements.ToArray();
                    chapters.Add(chapter);
                }
            }

            void NewChapter(HeaderBlock header)
            {
                // Add old
                AddChapter();
                // New chapter
                chapter = new ChapterData {
                    Title = header.ToString().Trim()
                };
                chapterElements = new List <MarkdownBlock>();
            }

            for (int i = 0; i < document.Blocks.Count; i++)
            {
                MarkdownBlock block = document.Blocks[i];
                if (debug)
                {
                    Console.Write($"{block.Type}: ", ConsoleColor.Cyan);
                }

                if (!IsCommentParagraph(block))
                {
                    elements.Add(block);
                }

                if (block is HeaderBlock header)
                {
                    if (header.HeaderLevel <= 2)
                    {
                        if (header.HeaderLevel == 1 && ad.TITLE == null)
                        {
                            ad.TITLE = header.ToString().Trim();
                        }
                        NewChapter(header);
                        continue;
                    }
                }

                if (!IsCommentParagraph(block))
                {
                    chapterElements.Add(block);
                }

                if (block is ParagraphBlock paragraph)
                {
                    if (debug)
                    {
                        Console.WriteLine();
                    }
                    for (int j = 0; j < paragraph.Inlines.Count; j++)
                    {
                        MarkdownInline inline = paragraph.Inlines[j];
                        if (debug)
                        {
                            Console.Write($"    {inline.Type}: ", ConsoleColor.DarkCyan);
                        }
                        if (debug)
                        {
                            Console.WriteLine(inline.ToString());
                        }
                        if (inline.Type != MarkdownInlineType.Comment)
                        {
                        }
                    }
                    if (debug)
                    {
                        Console.WriteLine("\n" + block.ToHtml());
                    }
                }
                else
                {
                    if (debug)
                    {
                        Console.WriteLine(block + "\n" + block.ToHtml());
                    }
                }
            }

            AddChapter();
            ad.CHAPTERS = chapters.ToArray();
            ad.ELEMENTS = elements.ToArray();

            return(ad);
        }
        /// <summary>
        /// 将块级元素转了 HTML
        /// </summary>
        /// <param name="block">MarkDown 块级元素</param>
        /// <returns>HTML</returns>
        public static string ToHtml(this MarkdownBlock block, string file, string innerText, string args = null)
        {
            var result = string.Empty;

            switch (block.Type)
            {
            case MarkdownBlockType.Code:
                var code   = block as CodeBlock;
                var lang   = string.IsNullOrEmpty(code.CodeLanguage) ? "" : $" class='{code.CodeLanguage.ToHlJs()}' lang='{HtmlEncode(code.CodeLanguage.ToHlJs())}'";
                var encode = HtmlEncode(code.Text);
                result += $"\r\n<figure class='highlight'>\r\n<button type='button' class='btn-clipboard' data-original-title='Copy to clipboard' data-clipboard-action='copy' data-toggle='tooltip' data-placement='top' title='Copy to clipboard' data-clipboard-text='{encode}'>Copy</button><pre><code{lang}>{encode}\r\n</code></pre>\r\n</figure>";
                break;

            case MarkdownBlockType.Header:
                var header = block as HeaderBlock;
                var _class = !string.IsNullOrEmpty(args) && args.StartsWith("collapse") && header.HeaderLevel == 2 ? " class='h2-collapse'" : "";
                int.TryParse(args, out int anchroPointCount);
                result += $"\r\n<h{header.HeaderLevel} id='{innerText.ToId(anchroPointCount)}'{_class}><span class='with-space bd-content-title'>";
                header.Inlines.ToList().ForEach(p => result += p.ToHtml(file));
                result += $"<a class='anchorjs-link' href='{innerText.ToAnchorPoint(anchroPointCount)}' aria-label='Anchor' data-anchorjs-icon='#'></a></span></h{header.HeaderLevel}>";
                break;

            case MarkdownBlockType.HorizontalRule: result += "\r\n<hr />"; break;

            case MarkdownBlockType.LinkReference:
                var linkReference = block as LinkReferenceBlock;
                var url           = linkReference.Url ?? "javascript:";
                var tooltip       = string.IsNullOrEmpty(linkReference.Tooltip) ? "" : $" title='{linkReference.Tooltip}'";
                if (url.IsExternalLink())
                {
                    result += $" <a class='with-space' href='{url}' target='_blank'{tooltip}>{linkReference}</a> ";
                }
                else
                {
                    result += $" <a class='with-space' href='{url.Replace(".md", ".html")}'{tooltip}>{linkReference}</a> ";
                }
                LinkCheck(file, url);
                break;

            case MarkdownBlockType.List:
                var list = block as ListBlock;
                if (list.Style == ListStyle.Bulleted)
                {
                    result += "\r\n<ul class='with-space'>";
                    list.Items.ToList().ForEach(l =>
                    {
                        result += $"\r\n<li>";
                        l.Blocks.ToList().ForEach(p => result += p.ToHtml(file, string.Empty));
                        result += $"</li>";
                    });
                    result += "\r\n</ul>";
                }
                if (list.Style == ListStyle.Numbered)
                {
                    result += "\r\n<ol>";
                    list.Items.ToList().ForEach(l =>
                    {
                        result += $"\r\n<li>";
                        l.Blocks.ToList().ForEach(p => result += p.ToHtml(file, string.Empty));
                        result += $"</li>";
                    });
                    result += "\r\n</ol>";
                }
                break;

            case MarkdownBlockType.Paragraph:
                result += "\r\n<p class='with-space'>";
                (block as ParagraphBlock).Inlines.ToList().ForEach(p => result += p.ToHtml(file));
                result += "</p>";
                break;

            case MarkdownBlockType.Quote:
                var blockQuote = block as QuoteBlock;
                for (int i = 0; i < blockQuote.Blocks.Count; i++)
                {
                    if (i == 0)
                    {
                        var    type = blockQuote.Blocks[0].ToString().ToUpper().Trim();
                        string style;
                        switch (type)
                        {
                        case "[!NOTE]":
                        case "[!INFO]":
                        case "[!TIP]":
                            style = " bd-callout-info"; break;

                        case "[!WARNING]":
                            style = " bd-callout-warning"; break;

                        case "[!IMPORTANT]":
                        case "[!DANGER]":
                        case "[!CAUTION]":
                            style = " bd-callout-danger"; break;

                        default: style = ""; break;
                        }
                        if (!string.IsNullOrEmpty(style))
                        {
                            result += $"\r\n<blockquote class='bd-callout{style} with-space'>";
                        }
                        else
                        {
                            result += $"\r\n<blockquote class='bd-callout with-space'>";
                            result += blockQuote.Blocks[i].ToHtml(file, string.Empty);
                        }
                    }
                    else
                    {
                        result += blockQuote.Blocks[i].ToHtml(file, string.Empty);
                    }
                }
                result += "\r\n</blockquote>";
                break;

            case MarkdownBlockType.Table:
                result += "\r\n<figure class='with-space'><table class='table table-hover'>";
                var table = block as TableBlock;
                for (int i = 0; i < table.Rows.Count; i++)
                {
                    var tr = table.Rows[i];
                    result += i == 0 ? "\r\n<thead>" : "";
                    result += i == 1 ? "\r\n<tbody>" : "";
                    result += "<tr>";
                    for (int j = 0; j < tr.Cells.Count; j++)
                    {
                        var td    = tr.Cells[j];
                        var style = string.Empty;
                        if (j < table.ColumnDefinitions.Count)
                        {
                            var align = table.ColumnDefinitions[j].Alignment;
                            style = align == ColumnAlignment.Unspecified ? "" : $" style='text-align:{align.ToString().ToLower()};'";
                        }
                        result += i == 0 ? $"<th{style}>" : $"<td{style}>";
                        td.Inlines.ToList().ForEach(p => result += p.ToHtml(file));
                        result += i == 0 ? "</th>" : "</td>";
                    }
                    result += "</tr>";
                    result += i == 0 ? "</thead>" : "";
                    result += i == table.Rows.Count - 1 ? "\r\n</tbody>" : "";
                }
                result += "\r\n</table></figure>";
                break;

            case MarkdownBlockType.YamlHeader:
                var yamlHeader = block as YamlHeaderBlock;
                result += "\r\n<figure><table class='table table-hover d-none'>";
                result += "\r\n<thead>\r\n<tr>";
                yamlHeader.Children.ToList().ForEach(p => result += $"<th>{p.Key}</th>");
                result += "\r\n</tr>\r\n</thead>";
                result += "\r\n<tbody>\r\n<tr>";
                yamlHeader.Children.ToList().ForEach(p => result += $"<td>{p.Value}</td>");
                result += "\r\n</tr>\r\n</tbody>";
                result += "\r\n</table></figure>";
                break;

            case MarkdownBlockType.Root:
            case MarkdownBlockType.ListItemBuilder:
                //这两个是啥?
                throw new NotImplementedException();

            default: break;
            }
            return(result);
        }
Exemple #28
0
        /// <summary>
        /// Markdown blocks processing
        /// </summary>
        /// <param name="b"></param>
        /// <param name="recursionLevel"></param>
        protected List <string> BlockProcessing(MarkdownBlock b, int recursionLevel)
        {
            string        forecolor = string.Empty;
            string        backcolor = string.Empty;
            string        underline = string.Empty;
            int           maxWidth  = client.screenWidth - recursionLevel * 2;
            List <string> Text      = new List <string>();

            switch (b.Type)
            {
            case MarkdownBlockType.Root:
                break;

            case MarkdownBlockType.Paragraph:
                string para = "";
                foreach (var i in ((ParagraphBlock)b).Inlines)
                {
                    para += ProcessInline(i);
                }
                Text.AddRange(TextHelper.WordWrap(para, maxWidth));
                Text.Add(string.Empty);
                break;

            case MarkdownBlockType.Quote:
                break;

            case MarkdownBlockType.Code:
                forecolor = ANSI.GetStyleForeColor("Code_Color", mdStyles);
                backcolor = ANSI.GetStyleBackColor("Code_Back", mdStyles);
                List <string> rows = TextHelper.SplitString(((CodeBlock)b).Text);
                foreach (string s in rows)
                {
                    Text.Add(backcolor + forecolor + ANSI.ClearCurrentLine + s + ANSI.WriteMode());
                }
                Text.Add(ANSI.WriteMode());
                break;

            case MarkdownBlockType.Header:
                HeaderBlock hb = (HeaderBlock)b;
                Text.AddRange(ANSI.Header(hb.ToString(), hb.HeaderLevel, maxWidth));
                break;

            case MarkdownBlockType.List:
                ListBlock lb     = (ListBlock)b;
                string    indent = new string(' ', recursionLevel * 2);
                foreach (var li in lb.Items)
                {
                    List <string> lir     = new List <string>();
                    bool          isFirst = true;
                    foreach (var lib in li.Blocks)
                    {
                        lir.AddRange(BlockProcessing(lib, recursionLevel + 1));
                    }
                    foreach (string s in lir)
                    {
                        Text.Add((isFirst ? "- " : "  ") + s);
                        isFirst = false;
                    }
                }
                break;

            case MarkdownBlockType.ListItemBuilder:
                break;

            case MarkdownBlockType.HorizontalRule:
                Text.Add(TextHelper.HR('-', maxWidth));
                break;

            case MarkdownBlockType.Table:
                TableBlock tb       = (TableBlock)b;
                int        colWidth = maxWidth / tb.ColumnDefinitions.Count;
                foreach (var tr in tb.Rows)
                {
                    string trs = string.Empty;
                    foreach (var tc in tr.Cells)
                    {
                        string tcs = string.Empty;
                        foreach (var i in tc.Inlines)
                        {
                            tcs += ProcessInline(i);
                        }
                        trs += TextHelper.Truncate(tcs, colWidth - 1).PadRight(colWidth);
                    }
                    Text.Add(trs);
                }
                break;

            case MarkdownBlockType.LinkReference:
                break;

            case MarkdownBlockType.YamlHeader:
                break;

            default:
                break;
            }
            return(Text);
        }
 private protected BlockParseResult(MarkdownBlock parsedElement, int start, int lineCount)
 {
     ParsedElement = parsedElement;
     Start         = start;
     LineCount     = lineCount;
 }
        private void AnalyzeHeader(MarkdownBlock element, RequirementSpecification data)
        {
            var header = element as HeaderBlock;

            if (header != null)
            {
                var text = header.ToString().Trim();
                switch (header.HeaderLevel)
                {
                case 1:
                    data.Title = text;
                    break;

                case 2:
                {
                    var info = ParseUtility.DecomposeHeading(header);
                    data.Requirements.Add(
                        new UpperRequirement
                        {
                            ID      = info.id,
                            Summary = info.summary
                        }
                        );
                }
                break;

                case 3:
                    if (text.Equals("理由"))
                    {
                        status = UsdmScope.UpperRequiremetReason;
                    }
                    else if (text.Equals("説明"))
                    {
                        status = UsdmScope.UpperRequiremetDescription;
                    }
                    else
                    {
                        var info = ParseUtility.DecomposeHeading(header);
                        data.Requirements.Last().Requirements.Add(
                            new LowerRequirement
                        {
                            ID      = info.id,
                            Summary = info.summary
                        }
                            );
                    }
                    break;

                case 4:
                    if (text.Equals("理由"))
                    {
                        status = UsdmScope.LowerRequiremetReason;
                    }
                    else if (text.Equals("説明"))
                    {
                        status = UsdmScope.LowerRequiremetDescription;
                    }
                    else if (text.Equals("仕様"))
                    {
                        status = UsdmScope.Specification;
                    }
                    break;

                default:
                    Console.WriteLine($"Text: {text}");
                    Console.WriteLine($"Level: {header.HeaderLevel}");
                    Console.WriteLine(element.ToString());
                    status = UsdmScope.None;
                    break;
                }
            }
        }