Esempio n. 1
0
        /// <summary>
        /// Adds a new block as child of another. Return the child.
        /// </summary>
        /// <remarks>Original: add_child</remarks>
        public static Block CreateChildBlock(Block parent, LineInfo line, BlockTag blockType, int startColumn)
        {
            // if 'parent' isn't the kind of block that can accept this child,
            // then back up til we hit a block that can.
            while (!CanContain(parent.Tag, blockType))
            {
                Finalize(parent, line);
                parent = parent.Parent;
            }

            var   startPosition = line.IsTrackingPositions ? line.CalculateOrigin(startColumn, true) : line.LineOffset;
            Block child         = new Block(blockType, startPosition)
            {
                Parent = parent,
                Top    = parent.Top
            };

            var lastChild = parent.LastChild;

            if (lastChild != null)
            {
                lastChild.NextSibling = child;
            }
            else
            {
                parent.FirstChild = child;
            }

            parent.LastChild = child;
            return(child);
        }
Esempio n. 2
0
        public static void Finalize(Block b, LineInfo line)
        {
            // don't do anything if the block is already closed
            if (!b.IsOpen)
            {
                return;
            }

            b.IsOpen = false;

            if (line.IsTrackingPositions)
            {
                // HTML Blocks other than type 7 call Finalize when the last line is encountered.
                // Block types 6 and 7 calls Finalize once it finds the next empty row but that empty row is no longer considered to be part of the block.
                var includesThisLine = b.HtmlBlockType != HtmlBlockType.None && b.HtmlBlockType != HtmlBlockType.InterruptingBlock && b.HtmlBlockType != HtmlBlockType.NonInterruptingBlock;

                // (b.SourcePosition >= line.LineOffset) determines if the block started on this line.
                includesThisLine = includesThisLine || b.SourcePosition >= line.LineOffset;

                if (includesThisLine && line.Line != null)
                {
                    b.SourceLastPosition = line.CalculateOrigin(line.Line.Length, false);
                }
                else
                {
                    b.SourceLastPosition = line.CalculateOrigin(0, false);
                }
            }

            switch (b.Tag)
            {
            case BlockTag.Paragraph:
                var sc = b.StringContent;
                if (!sc.StartsWith('['))
                {
                    break;
                }

                var subj = new Subject(b.Top.Document);
                sc.FillSubject(subj);
                var origPos = subj.Position;
                while (subj.Position < subj.Buffer.Length &&
                       subj.Buffer[subj.Position] == '[' &&
                       0 != InlineMethods.ParseReference(subj))
                {
                }

                if (subj.Position != origPos)
                {
                    sc.Replace(subj.Buffer, subj.Position, subj.Buffer.Length - subj.Position);

                    if (sc.PositionTracker != null)
                    {
                        sc.PositionTracker.AddBlockOffset(subj.Position - origPos);
                    }

                    if (Utilities.IsFirstLineBlank(subj.Buffer, subj.Position))
                    {
                        b.Tag = BlockTag.ReferenceDefinition;
                    }
                }

                break;

            case BlockTag.IndentedCode:
                b.StringContent.RemoveTrailingBlankLines();
                break;

            case BlockTag.FencedCode:
                // first line of contents becomes info
                var firstlinelen = b.StringContent.IndexOf('\n') + 1;
                b.FencedCodeData.Info = InlineMethods.Unescape(b.StringContent.TakeFromStart(firstlinelen, true).Trim());
                break;

            case BlockTag.List:            // determine tight/loose status
                b.ListData.IsTight = true; // tight by default
                var   item = b.FirstChild;
                Block subitem;

                while (item != null)
                {
                    // check for non-final non-empty list item ending with blank line:
                    if (item.IsLastLineBlank && item.NextSibling != null)
                    {
                        b.ListData.IsTight = false;
                        break;
                    }

                    // recurse into children of list item, to see if there are spaces between them:
                    subitem = item.FirstChild;
                    while (subitem != null)
                    {
                        if (EndsWithBlankLine(subitem) && (item.NextSibling != null || subitem.NextSibling != null))
                        {
                            b.ListData.IsTight = false;
                            break;
                        }

                        subitem = subitem.NextSibling;
                    }

                    if (!b.ListData.IsTight)
                    {
                        break;
                    }

                    item = item.NextSibling;
                }

                break;
            }
        }