UniversalMarkdown.Parse.Elements.ListBlock.Parse C# (CSharp) Method

Parse() static private method

Parses a list block.
static private Parse ( string markdown, int start, int maxEnd, int quoteDepth, int &actualEnd ) : ListBlock
markdown string The markdown text.
start int The location of the first character in the block.
maxEnd int The location to stop parsing.
quoteDepth int The current nesting level for block quoting.
actualEnd int Set to the end of the block when the return value is non-null.
return ListBlock
        internal static ListBlock Parse(string markdown, int start, int maxEnd, int quoteDepth, out int actualEnd)
        {
            var russianDolls = new List<NestedListInfo>();
            int russianDollIndex = -1;
            bool previousLineWasBlank = false;
            ListItemBlock currentListItem = null;
            actualEnd = start;

            foreach (var lineInfo in Common.ParseLines(markdown, start, maxEnd, quoteDepth))
            {
                // Is this line blank?
                if (lineInfo.IsLineBlank)
                {
                    // The line is blank, which means the next line which contains text may end the list (or it may not...).
                    previousLineWasBlank = true;
                }
                else
                {
                    // Does the line contain a list item?
                    ListItemPreamble listItemPreamble = null;
                    if (lineInfo.FirstNonWhitespaceChar - lineInfo.StartOfLine < (russianDollIndex + 2) * 4)
                        listItemPreamble = ParseItemPreamble(markdown, lineInfo.FirstNonWhitespaceChar, lineInfo.EndOfLine);
                    if (listItemPreamble != null)
                    {
                        // Yes, this line contains a list item.

                        // Determining the nesting level is done as follows:
                        // 1. If this is the first line, then the list is not nested.
                        // 2. If the number of spaces at the start of the line is equal to that of
                        //    an existing list, then the nesting level is the same as that list.
                        // 3. Otherwise, if the number of spaces is 0-4, then the nesting level
                        //    is one level deep.
                        // 4. Otherwise, if the number of spaces is 5-8, then the nesting level
                        //    is two levels deep (but no deeper than one level more than the
                        //    previous list item).
                        // 5. Etcetera.
                        ListBlock listToAddTo = null;
                        int spaceCount = lineInfo.FirstNonWhitespaceChar - lineInfo.StartOfLine;
                        russianDollIndex = russianDolls.FindIndex(rd => rd.SpaceCount == spaceCount);
                        if (russianDollIndex >= 0)
                        {
                            // Add the new list item to an existing list.
                            listToAddTo = russianDolls[russianDollIndex].List;

                            // Don't add new list items to items higher up in the list.
                            russianDolls.RemoveRange(russianDollIndex + 1, russianDolls.Count - (russianDollIndex + 1));
                        }
                        else
                        {
                            russianDollIndex = Math.Max(1, 1 + (spaceCount - 1) / 4);
                            if (russianDollIndex < russianDolls.Count)
                            {
                                // Add the new list item to an existing list.
                                listToAddTo = russianDolls[russianDollIndex].List;

                                // Don't add new list items to items higher up in the list.
                                russianDolls.RemoveRange(russianDollIndex + 1, russianDolls.Count - (russianDollIndex + 1));
                            }
                            else
                            {
                                // Create a new list.
                                listToAddTo = new ListBlock { Style = listItemPreamble.Style, Items = new List<ListItemBlock>() };
                                if (russianDolls.Count > 0)
                                    currentListItem.Blocks.Add(listToAddTo);
                                russianDollIndex = russianDolls.Count;
                                russianDolls.Add(new NestedListInfo { List = listToAddTo, SpaceCount = spaceCount });
                            }
                        }

                        // Add a new list item.
                        currentListItem = new ListItemBlock() { Blocks = new List<MarkdownBlock>() };
                        listToAddTo.Items.Add(currentListItem);

                        // Add the rest of the line to the builder.
                        AppendTextToListItem(currentListItem, markdown, listItemPreamble.ContentStartPos, lineInfo.EndOfLine);
                    }
                    else
                    {
                        // No, this line contains text.

                        // Is there even a list in progress?
                        if (currentListItem == null)
                        {
                            actualEnd = start;
                            return null;
                        }

                        // 0 spaces = end of the list.
                        // 1-4 spaces = first level.
                        // 5-8 spaces = second level, etc.
                        if (previousLineWasBlank)
                        {
                            // This is the start of a new paragraph.
                            int spaceCount = lineInfo.FirstNonWhitespaceChar - lineInfo.StartOfLine;
                            if (spaceCount == 0)
                                break;
                            russianDollIndex = Math.Min(russianDollIndex, (spaceCount - 1) / 4);
                            ListBlock listToAddTo = russianDolls[russianDollIndex].List;
                            currentListItem = listToAddTo.Items[listToAddTo.Items.Count - 1];
                            currentListItem.Blocks.Add(new ListItemBuilder());
                            AppendTextToListItem(currentListItem, markdown, Math.Min(lineInfo.FirstNonWhitespaceChar, lineInfo.StartOfLine + (russianDollIndex + 1) * 4), lineInfo.EndOfLine);
                        }
                        else
                        {
                            // Inline text.
                            AppendTextToListItem(currentListItem, markdown, lineInfo.FirstNonWhitespaceChar, lineInfo.EndOfLine);
                        }
                    }

                    // The line was not blank.
                    previousLineWasBlank = false;
                }

                // Go to the next line.
                actualEnd = lineInfo.EndOfLine;
            }

            var result = russianDolls[0].List;
            ReplaceStringBuilders(result);
            return result;
        }