/// <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; #pragma warning disable 0618 Block child = new Block(blockType, line.LineNumber, startColumn + 1, startPosition); #pragma warning restore 0618 child.Parent = parent; child.Top = parent.Top; var lastChild = parent.LastChild; if (lastChild != null) { lastChild.NextSibling = child; #pragma warning disable 0618 child.Previous = lastChild; #pragma warning restore 0618 } else { parent.FirstChild = child; } parent.LastChild = child; return(child); }
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); } } #pragma warning disable 0618 b.EndLine = (line.LineNumber > b.StartLine) ? line.LineNumber - 1 : line.LineNumber; #pragma warning restore 0618 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; } }