예제 #1
0
        public static void ProcessStage2(Syntax.Block document, CommonMarkSettings settings = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException("document");
            }

            if (document.Tag != Syntax.BlockTag.Document)
            {
                throw new ArgumentException("The block element passed to this method must represent a top level document.", "document");
            }

            if (settings == null)
            {
                settings = CommonMarkSettings.Default;
            }

            try
            {
                BlockMethods.ProcessInlines(document, document.ReferenceMap, settings);
            }
            catch (CommonMarkException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new CommonMarkException("An error occurred during inline parsing.", ex);
            }
        }
예제 #2
0
        public static void ProcessStage2(Syntax.Block document, CommonMarkSettings settings = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException(document.ToString());
            }

            if (document.Tag != Syntax.BlockTag.Document)
            {
                throw new ArgumentException("Блочный элемент, предоставляемый методу, должен быть высокоуровневым документом.", document.ToString());
            }

            if (settings == null)
            {
                settings = CommonMarkSettings.Default;
            }

            try
            {
                BlockMethods.ProcessInlines(document, document.ReferenceMap, settings);
            }
            catch (CommonMarkException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new CommonMarkException("Ошибка при инлайн-парсинге.", ex);
            }
        }
예제 #3
0
        public static bool PositionSafeForSmartLink(Block ast, int start, int length)
        {
            if (ast == null) return true;
            var end = start + length;
            var blockTags = new[] {BlockTag.FencedCode, BlockTag.HtmlBlock, BlockTag.IndentedCode, BlockTag.ReferenceDefinition};
            var inlineTags = new[] {InlineTag.Code, InlineTag.Link, InlineTag.RawHtml, InlineTag.Image};
            var lastBlockTag = BlockTag.Document;

            foreach (var block in EnumerateBlocks(ast.FirstChild))
            {
                if (block.SourcePosition + block.SourceLength < start)
                {
                    lastBlockTag = block.Tag;
                    continue;
                }

                if (block.SourcePosition >= end) return !blockTags.Any(tag => tag == lastBlockTag);
                if (blockTags.Any(tag => tag == block.Tag)) return false;

                return !EnumerateInlines(block.InlineContent)
                    .TakeWhile(il => il.SourcePosition < end)
                    .Where(il => il.SourcePosition + il.SourceLength > start)
                    .Any(il => inlineTags.Any(tag => tag == il.Tag));
            }
            return true;
        }
예제 #4
0
        public static void ProcessStage3(Syntax.Block document, TextWriter target, CommonMarkSettings settings = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException(document.ToString());
            }

            if (target == null)
            {
                throw new ArgumentNullException(target.ToString());
            }

            if (document.Tag != Syntax.BlockTag.Document)
            {
                throw new ArgumentException("Блочный элемент, предоставляемый методу, болжен быть высокоуровневым документом.", document.ToString());
            }

            if (settings == null)
            {
                settings = CommonMarkSettings.Default;
            }

            try
            {
                switch (settings.OutputFormat)
                {
                case OutputFormat.Html:
                    HtmlFormatterSlim.BlocksToHtml(target, document, settings);
                    break;

                case OutputFormat.SyntaxTree:
                    Printer.PrintBlocks(target, document, settings);
                    break;

                case OutputFormat.CustomDelegate:
                    if (settings.OutputDelegate == null)
                    {
                        throw new CommonMarkException("Если `settings.OutputFormat` установлен в `CustomDelegate`, свойство `settings.OutputDelegate` должно быть заполнено.");
                    }
                    settings.OutputDelegate(document, target, settings);
                    break;

                default:
                    throw new CommonMarkException("Неподдерживаемое значение '" + settings.OutputFormat + "' в `settings.OutputFormat`.");
                }
            }
            catch (CommonMarkException)
            {
                throw;
            }
            catch (IOException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new CommonMarkException("Ошибка при форматировании документа.", ex);
            }
        }
예제 #5
0
        public static void ProcessStage3(Syntax.Block document, TextWriter target, CommonMarkSettings settings = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException("document");
            }

            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            if (document.Tag != Syntax.BlockTag.Document)
            {
                throw new ArgumentException("The block element passed to this method must represent a top level document.", "document");
            }

            if (settings == null)
            {
                settings = CommonMarkSettings.Default;
            }

            try
            {
                switch (settings.OutputFormat)
                {
                case OutputFormat.Html:
                    HtmlFormatterSlim.BlocksToHtml(target, document, settings);
                    break;

                case OutputFormat.SyntaxTree:
                    Printer.PrintBlocks(target, document, settings);
                    break;

                case OutputFormat.CustomDelegate:
                    if (settings.OutputDelegate == null)
                    {
                        throw new CommonMarkException("If `settings.OutputFormat` is set to `CustomDelegate`, the `settings.OutputDelegate` property must be populated.");
                    }
                    settings.OutputDelegate(document, target, settings);
                    break;

                default:
                    throw new CommonMarkException("Unsupported value '" + settings.OutputFormat + "' in `settings.OutputFormat`.");
                }
            }
            catch (CommonMarkException)
            {
                throw;
            }
            catch (IOException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new CommonMarkException("An error occurred during formatting of the document.", ex);
            }
        }
예제 #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TopicParserResult"/> class.
 /// </summary>
 /// <param name="doc">Document block.</param>
 internal TopicParserResult(Block doc)
 {
     if (doc == null)
         throw new ArgumentNullException("doc");
     if (doc.Tag != BlockTag.Document)
         throw new InvalidOperationException("Unexpected block tag: " + doc.Tag);
     Document = doc;
 }
예제 #7
0
 public async Task WriteAsync(Block block)
 {
     await WriteStartElementAsync("para");
     await WriteStartElementAsync("command");
     await WriteChildInlinesAsync(block);
     await WriteEndElementAsync(); //command
     await WriteEndElementAsync(); //para
 }
예제 #8
0
 private static string GetTitle(TopicData topic, Block block)
 {
     if (block == null || block.HeaderLevel != 1)
         return topic.Name;
     var title = string.Empty;
     for (var inline = block.InlineContent; inline != null; inline = inline.NextSibling)
         title += inline.LiteralContent;
     return title;
 }
예제 #9
0
        /// <summary>
        /// Creates a new top-level document block.
        /// </summary>
        internal static Block CreateDocument()
        {
#pragma warning disable 0618
            Block e = new Block(BlockTag.Document, 1, 1, 0);
#pragma warning restore 0618
            e.ReferenceMap = new Dictionary<string, Reference>();
            e.Top = e;
            return e;
        }
예제 #10
0
 internal override async Task<SectionState> DoWriteStartSectionAsync(Block block, string title)
 {
     await WriteStartElementAsync("glossaryEntry");
     await WriteStartElementAsync("terms");
     foreach (var term in title.Split(','))
         await WriteTermAsync(term);
     await WriteEndElementAsync(); //terms
     await WriteStartElementAsync("definition");
     return SectionState.Content;
 }
예제 #11
0
 private static void PrintPosition(bool enabled, TextWriter writer, Block block)
 {
     if (enabled)
     {
         writer.Write(" [");
         writer.Write(block.SourcePosition);
         writer.Write('-');
         writer.Write(block.SourceLastPosition);
         writer.Write(']');
     }
 }
        public void WriteChainedInlineHeader()
        {
            // Process
            Block block = new Block(BlockTag.AtxHeader, 0);
            block.InlineContent = new Inline("Title");
            block.InlineContent.NextSibling = new Inline(" in many");
            block.InlineContent.NextSibling.NextSibling = new Inline(" siblings");
            string output = this.Process(block);

            // Assert
            Assert.AreEqual(string.Format(@"<!--UT [Title in many siblings](page-title-in-many-siblings)-->{0}<h0>Title in many siblings</h0>{0}", Environment.NewLine), output);
        }
예제 #13
0
 public static IEnumerable<Block> EnumerateBlocks(Block block)
 {
     if (block == null) yield break;
     var stack = new Stack<Block>();
     stack.Push(block);
     while (stack.Any())
     {
         var next = stack.Pop();
         yield return next;
         if (next.NextSibling != null) stack.Push(next.NextSibling);
         if (next.FirstChild != null) stack.Push(next.FirstChild);
     }
 }
예제 #14
0
        internal override async Task WriteListItemAsync(Block block)
        {
            if (GetSectionState() != SectionState.Sections)
            {
                await base.WriteListItemAsync(block);
                return;
            }

            await WriteStartElementAsync("step");
            await WriteStartElementAsync("content");
            await WriteChildBlocksAsync(block);
            await WriteEndElementAsync(); //content
            await WriteEndElementAsync(); //step
        }
예제 #15
0
        public FlowDocument BlocksToXaml(Block block, CommonMarkSettings settings)
        {
            //_checkBoxNumber = 0;
            FlowDocument document = new FlowDocument();

            document.PagePadding = new Thickness(0);
            if (DocumentStyle != null)
            {
                document.Style = DocumentStyle;
            }

            BlocksToXamlInner(document, block, settings);

            return(document);
        }
        public void WriteChainedInlineHeader()
        {
            // Process
            Block block = new Block(BlockTag.AtxHeader, 0);
            block.InlineContent = new Inline("Title");
            block.InlineContent.NextSibling = new Inline(" in many");
            block.InlineContent.NextSibling.NextSibling = new Inline(" siblings");
            string output = this.Process(block);

            // Assert
            Assert.IsTrue(output.StartsWith(@"<a name=""page-title+in+many+siblings"">"));
            Assert.AreEqual(1, this.Formatter.Anchors.Length);
            Assert.AreEqual("page-title+in+many+siblings", this.Formatter.Anchors[0].Value);
            Assert.AreEqual("Title in many siblings", this.Formatter.Anchors[0].Label);
            Assert.AreEqual(0, this.Formatter.Anchors[0].Level);
        }
예제 #17
0
        public static FlowDocument Format(
            CMBlock block,
            Func <string, string> urlResolver         = null,
            Func <string, string> placeholderResolver = null)
        {
            var document = new FlowDocument();

            FormatBlocks(
                new Settings {
                UrlResolver         = urlResolver,
                PlaceholderResolver = placeholderResolver,
            },
                block.FirstChild,
                document.Blocks);
            return(document);
        }
예제 #18
0
        /// <summary>
        /// Check to see if a block ends with a blank line, descending if needed into lists and sublists.
        /// </summary>
        private static bool EndsWithBlankLine(Block block)
        {
            while (true)
            {
                if (block.IsLastLineBlank)
                    return true;

                if (block.Tag != BlockTag.List && block.Tag != BlockTag.ListItem)
                    return false;

                block = block.LastChild;

                if (block == null)
                    return false;
            }
        }
예제 #19
0
        internal override async Task WriteListAsync(Block block)
        {
            if (SectionLevel < 2)
            {
                await base.WriteListAsync(block);
                return;
            }

            await WriteEndIntroductionAsync();

            //TODO procedure?
            await WriteStartElementAsync("steps");
            await WriteListClassAsync(block, ListClass.Bullet);
            SetSectionState(SectionState.Sections);
            await WriteChildBlocksAsync(block);
            await WriteEndElementAsync(); //steps
        }
        public static void ProcessStage3(Syntax.Block document, TextWriter target, CommonMarkSettings settings = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException("document");
            }

            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            if (document.Tag != Syntax.BlockTag.Document)
            {
                throw new ArgumentException("The block element passed to this method must represent a top level document.", "document");
            }

            if (settings == null)
            {
                settings = CommonMarkSettings.Default;
            }

            try
            {
                if (settings.OutputFormat == OutputFormat.SyntaxTree)
                {
                    Printer.PrintBlocks(target, document, settings);
                }
                else
                {
                    HtmlPrinter.BlocksToHtml(target, document, settings);
                }
            }
            catch (CommonMarkException)
            {
                throw;
            }
            catch (IOException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new CommonMarkException("An error occurred during formatting of the document.", ex);
            }
        }
예제 #21
0
        /// <summary>
        /// Specializes block writing for anchor injection.
        /// For each formatted header we generate an anchor based on the context name, the header content and eventually add an integer suffix in order to prevent conflicts.
        /// </summary>
        /// <param name="block">The block to process.</param>
        /// <param name="isOpening">Define whether the block is opening.</param>
        /// <param name="isClosing">Defines whether the block is closing.</param>
        /// <param name="ignoreChildNodes">return whether the processing ignored child nodes.</param>
        protected override void WriteBlock(Block block, bool isOpening, bool isClosing, out bool ignoreChildNodes)
        {
            // Filter opening header
            if (isOpening && null != block && block.Tag == BlockTag.AtxHeader)
            {
                // Retrieve header content
                string headerContent;
                if (null != block.InlineContent && null != block.InlineContent.LiteralContent)
                {
                    // Read the whole content
                    Inline inline = block.InlineContent;
                    StringBuilder stringBuilder = new StringBuilder();
                    do
                    {
                        stringBuilder.Append(inline.LiteralContent);
                        inline = inline.NextSibling;
                    } while (null != inline);
                    headerContent = stringBuilder.ToString();
                }
                else
                {
                    headerContent = "unknown";
                }

                // Compute the anchor value
                string sectionId = HttpUtility.UrlEncode(headerContent.ToLower());
                sectionId = string.Format("{0}-{1}", this.ContextName, sectionId)
                    .Replace('+', '-');

                // Detect anchor conflict
                if (sectionConflict.ContainsKey(sectionId))
                {
                    // Append the index
                    sectionId = string.Format("{0}-{1}", sectionId, ++sectionConflict[sectionId]);
                }

                // Write anchor
                this.Write(string.Format(@"<!--{0} [{1}]({2})-->", this.PageSplittingIdentifier, headerContent, sectionId));
                sectionConflict[sectionId] = 1;
            }

            // Trigger parent rendering for the default html rendering
            base.WriteBlock(block, isOpening, isClosing, out ignoreChildNodes);
        }
예제 #22
0
        /// <summary>
        /// Writes the given CommonMark document to the output stream as HTML.
        /// </summary>
        public void WriteDocument(Block document)
        {
            if (document == null)
                throw new ArgumentNullException(nameof(document));

            bool ignoreChildNodes;
            Block ignoreUntilBlockCloses = null;
            Inline ignoreUntilInlineCloses = null;

            foreach (var node in document.AsEnumerable())
            {
                if (node.Block != null)
                {
                    if (ignoreUntilBlockCloses != null)
                    {
                        if (ignoreUntilBlockCloses != node.Block)
                            continue;

                        ignoreUntilBlockCloses = null;
                    }

                    WriteBlock(node.Block, node.IsOpening, node.IsClosing, out ignoreChildNodes);
                    if (ignoreChildNodes && !node.IsClosing)
                        ignoreUntilBlockCloses = node.Block;
                }
                else if (ignoreUntilBlockCloses == null && node.Inline != null)
                {
                    if (ignoreUntilInlineCloses != null)
                    {
                        if (ignoreUntilInlineCloses != node.Inline)
                            continue;

                        ignoreUntilInlineCloses = null;
                    }

                    WriteInline(node.Inline, node.IsOpening, node.IsClosing, out ignoreChildNodes);
                    if (ignoreChildNodes && !node.IsClosing)
                        ignoreUntilInlineCloses = node.Inline;
                }
            }
        }
예제 #23
0
        /// <summary>
        /// Break out of all containing lists
        /// </summary>
        private static void BreakOutOfLists(ref Block blockRef, LineInfo line)
        {
            Block container = blockRef;
            Block b = container.Top;

            // find first containing list:
            while (b != null && b.Tag != BlockTag.List)
                b = b.LastChild;

            if (b != null)
            {
                while (container != null && container != b)
                {
                    Finalize(container, line);
                    container = container.Parent;
                }

                Finalize(b, line);
                blockRef = b.Parent;
            }
        }
예제 #24
0
        private static void BlockToDocumentBlock(CommonMark.Syntax.Block block, ListItemCollection collection)
        {
            if (block == null)
            {
                return;
            }

            switch (block.Tag)
            {
            case BlockTag.ListItem:
                var listitemBlock = new ListItem();

                collection.Add(listitemBlock);
                BlockToDocumentBlock(block.FirstChild, listitemBlock.Blocks);
                BlockToDocumentBlock(block.NextSibling, collection);
                break;

            default:
                throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block);
            }
        }
예제 #25
0
        static void FormatBlocks(Settings settings, CMBlock cmBlock, BlockCollection wdBlocks)
        {
            for (; cmBlock != null; cmBlock = cmBlock.NextSibling)
            {
                switch (cmBlock.Tag)
                {
                case BlockTag.AtxHeading:
                case BlockTag.SetextHeading:
                case BlockTag.Paragraph:
                    var wdParagraph = new Paragraph();
                    if (cmBlock.Tag != BlockTag.Paragraph)
                    {
                        // FIXME: this should probably be a Section with header
                        // level stored in Section.Tag or a custom style so it
                        // can be configured in XAML. Out of time.
                        wdParagraph.FontWeight = FontWeights.Bold;
                        wdParagraph.FontSize   = 14;
                    }
                    FormatInlines(settings, cmBlock.InlineContent, wdParagraph.Inlines);
                    wdBlocks.Add(wdParagraph);
                    break;

                case BlockTag.List:
                    var wdList = new List();
                    for (var cmChildBlock = cmBlock.FirstChild;
                         cmChildBlock != null;
                         cmChildBlock = cmChildBlock.NextSibling)
                    {
                        var wdListItem = new ListItem();
                        FormatBlocks(settings, cmChildBlock.FirstChild, wdListItem.Blocks);
                        wdList.ListItems.Add(wdListItem);
                    }
                    wdBlocks.Add(wdList);
                    break;

                default:
                    throw new NotImplementedException($"BlockTag.{cmBlock.Tag}");
                }
            }
        }
예제 #26
0
        private static void AddLine(Block block, LineInfo lineInfo, string ln, int offset, int length = -1)
        {
            if (!block.IsOpen)
                throw new CommonMarkException(string.Format(CultureInfo.InvariantCulture, "Attempted to add line '{0}' to closed container ({1}).", ln, block.Tag));

            var len = length == -1 ? ln.Length - offset : length;
            if (len <= 0)
                return;

            var curSC = block.StringContent;
            if (curSC == null)
            {
                block.StringContent = curSC = new StringContent();
                if (lineInfo.IsTrackingPositions)
                    curSC.PositionTracker = new PositionTracker(lineInfo.LineOffset);
            }

            if (lineInfo.IsTrackingPositions)
                curSC.PositionTracker.AddOffset(lineInfo, offset, len);

            curSC.Append(ln, offset, len);
        }
예제 #27
0
 public static IEnumerable<Block> EnumerateSpanningBlocks(Block ast, int startOffset, int endOffset)
 {
     return EnumerateBlocks(ast.FirstChild)
         .Where(b => (b.SourcePosition + b.SourceLength) > startOffset)
         .TakeWhile(b => b.SourcePosition < endOffset);
 }
 public void OnTextChanged(string text)
 {
     var ast = ParseDocument(text);
     _abstractSyntaxTree = ast;
 }
예제 #29
0
 /// <summary>
 /// Writes a <c>data-sourcepos="start-end"</c> attribute to the target writer. 
 /// This method should only be called if <see cref="CommonMarkSettings.TrackSourcePosition"/> is set to <see langword="true"/>.
 /// Note that the attribute is preceded (but not succeeded) by a single space.
 /// </summary>
 protected void WritePositionAttribute(Block block)
 {
     HtmlFormatterSlim.PrintPosition(_target, block);
 }
        /// <summary>
        /// Specializes block writing for anchor injection.
        /// For each formatted header we generate an anchor based on the context name, the header content and eventually add an integer suffix in order to prevent conflicts.
        /// </summary>
        /// <param name="block">The block to process.</param>
        /// <param name="isOpening">Define whether the block is opening.</param>
        /// <param name="isClosing">Defines whether the block is closing.</param>
        /// <param name="ignoreChildNodes">return whether the processing ignored child nodes.</param>
        protected override void WriteBlock(Block block, bool isOpening, bool isClosing, out bool ignoreChildNodes)
        {
            // Filter opening header
            if (isOpening && null != block && block.Tag == BlockTag.AtxHeader)
            {
                // Retrieve header content
                string headerContent;
                if (null != block.InlineContent && null != block.InlineContent.LiteralContent)
                {
                    // Read the whole content
                    Inline inline = block.InlineContent;
                    StringBuilder stringBuilder = new StringBuilder();
                    do
                    {
                        stringBuilder.Append(inline.LiteralContent);
                        inline = inline.NextSibling;
                    } while (null != inline);
                    headerContent = stringBuilder.ToString();
                }
                else
                {
                    headerContent = "unknown";
                }

                // Compute the anchor value
                string anchor = string.Format("{0}-{1}", this.ContextName, headerContent).ToLower();

                // Encode for url usage
                anchor = HttpUtility.UrlEncode(anchor);

                // Detect anchor conflict
                if (anchors.ContainsKey(anchor))
                {
                    // Compute an index to resolve conflicts
                    int index;
                    if (anchorConflicts.ContainsKey(anchor))
                    {
                        index = ++anchorConflicts[anchor];
                    }
                    else
                    {
                        index = anchorConflicts[anchor] = 2;
                    }

                    // Append the index
                    anchor = string.Format("{0}-{1}", anchor, index);
                }

                // Write anchor
                this.Write(string.Format(@"<a name=""{0}""></a>", anchor));

                // Keep track of the created anchor
                anchors[anchor] = new Anchor(
                    label: headerContent,
                    level: block.HeaderLevel,
                    value: anchor);
            }

            // Trigger parent rendering for the default html rendering
            base.WriteBlock(block, isOpening, isClosing, out ignoreChildNodes);
        }
예제 #31
0
 internal override async Task WriteRelatedTopicsAsync(Block block)
 {
     await WriteEndElementAsync(); //glossary
 }
예제 #32
0
 public static void BlocksToFlowDocument(CommonMark.Syntax.Block blocks, FlowDocument document)
 {
     BlockToDocumentBlock(blocks, document.Blocks);
 }
예제 #33
0
        /// <summary>
        /// Walk through the block, its children and siblings, parsing string content into inline content where appropriate.
        /// </summary>
        /// <param name="block">The document level block from which to start the processing.</param>
        /// <param name="refmap">The reference mapping used when parsing links.</param>
        /// <param name="settings">The settings that influence how the inline parsing is performed.</param>
        public static void ProcessInlines(Block block, Dictionary<string, Reference> refmap, CommonMarkSettings settings)
        {
            Stack<Inline> inlineStack = null;
            var stack = new Stack<Block>();
            var parsers = settings.InlineParsers;
            var specialCharacters = settings.InlineParserSpecialCharacters;
            var subj = new Subject(refmap);

            StringContent sc;
            int delta;

            while (block != null)
            {
                var tag = block.Tag;
                if (tag == BlockTag.Paragraph || tag == BlockTag.AtxHeader || tag == BlockTag.SETextHeader)
                {
                    sc = block.StringContent;
                    if (sc != null)
                    {
                        sc.FillSubject(subj);
                        delta = subj.Position;

                        block.InlineContent = InlineMethods.parse_inlines(subj, refmap, parsers, specialCharacters);
                        block.StringContent = null;

                        if (sc.PositionTracker != null)
                        {
                            sc.PositionTracker.AddBlockOffset(-delta);
                            AdjustInlineSourcePosition(block.InlineContent, sc.PositionTracker, ref inlineStack);
                        }
                    }
                }

                if (block.FirstChild != null)
                {
                    if (block.NextSibling != null)
                        stack.Push(block.NextSibling);

                    block = block.FirstChild;
                }
                else if (block.NextSibling != null)
                {
                    block = block.NextSibling;
                }
                else if (stack.Count > 0)
                {
                    block = stack.Pop();
                }
                else
                {
                    block = null;
                }
            }
        }
예제 #34
0
        private void WriteTable(Block table, IAddChild parent, CommonMarkSettings settings, Stack <InlineStackEntry> stack)
        {
            if ((settings.AdditionalFeatures & CommonMarkAdditionalFeatures.GithubStyleTables) == 0)
            {
                throw new CommonMarkException("Table encountered in AST, but GithubStyleTables are not enabled");
            }

            var header   = table.FirstChild;
            var firstRow = table.FirstChild.NextSibling;

            Table t = new Table();

            parent.AddChild(t);

            if (TableStyle != null)
            {
                t.Style = TableStyle;
            }

            var tableHeadRowGroup = new TableRowGroup();

            t.RowGroups.Add(tableHeadRowGroup);
            TableRow headRow = new TableRow();

            if (TableHeadStyle != null)
            {
                headRow.Style = TableHeadStyle;
            }
            tableHeadRowGroup.Rows.Add(headRow);

            var numHeadings = 0;

            var curHeaderCell = header.FirstChild;

            while (curHeaderCell != null)
            {
                if (numHeadings >= table.TableHeaderAlignments.Length)
                {
                    break;
                }

                var alignment = table.TableHeaderAlignments[numHeadings];

                numHeadings++;

                TableCell cell = new TableCell();
                if (TableCellStyle != null)
                {
                    cell.Style = TableCellStyle;
                }

                InlinesToXaml(cell, curHeaderCell.InlineContent, settings, stack);

                if (alignment != TableHeaderAlignment.None)
                {
                    switch (alignment)
                    {
                    case TableHeaderAlignment.Center: cell.TextAlignment = TextAlignment.Center; break;

                    case TableHeaderAlignment.Left: cell.TextAlignment = TextAlignment.Left; break;

                    case TableHeaderAlignment.Right: cell.TextAlignment = TextAlignment.Right; break;

                    default: throw new CommonMarkException("Unexpected TableHeaderAlignment [" + alignment + "]");
                    }
                }

                headRow.Cells.Add(cell);

                curHeaderCell = curHeaderCell.NextSibling;
            }

            var tableBodyRowGroup = new TableRowGroup();

            t.RowGroups.Add(tableBodyRowGroup);

            var curRow = firstRow;

            while (curRow != null)
            {
                TableRow row = new TableRow();
                if (TableRowStyle != null)
                {
                    row.Style = TableRowStyle;
                }

                tableBodyRowGroup.Rows.Add(row);

                var curRowCell = curRow.FirstChild;

                var numCells = 0;

                while (curRowCell != null && numCells < numHeadings)
                {
                    var alignment = table.TableHeaderAlignments[numCells];

                    numCells++;

                    TableCell cell = new TableCell();
                    if (TableCellStyle != null)
                    {
                        cell.Style = TableCellStyle;
                    }

                    row.Cells.Add(cell);

                    if (alignment != TableHeaderAlignment.None)
                    {
                        switch (alignment)
                        {
                        case TableHeaderAlignment.Center: cell.TextAlignment = TextAlignment.Center; break;

                        case TableHeaderAlignment.Left: cell.TextAlignment = TextAlignment.Left; break;

                        case TableHeaderAlignment.Right: cell.TextAlignment = TextAlignment.Right; break;

                        default: throw new CommonMarkException("Unexpected TableHeaderAlignment [" + alignment + "]");
                        }
                    }

                    InlinesToXaml(cell, curRowCell.InlineContent, settings, stack);

                    curRowCell = curRowCell.NextSibling;
                }

                while (numCells < numHeadings)
                {
                    numCells++;

                    TableCell cell = new TableCell();
                    if (TableCellStyle != null)
                    {
                        cell.Style = TableCellStyle;
                    }

                    row.Cells.Add(cell);
                }

                curRow = curRow.NextSibling;
            }
        }
예제 #35
0
        private void BlocksToXamlInner(FlowDocument parent, Block block, CommonMarkSettings settings)
        {
            _checkBoxNumber = 0;
            var  stack          = new Stack <BlockStackEntry>();
            var  inlineStack    = new Stack <InlineStackEntry>();
            bool stackTight     = false;
            bool tight          = false;
            bool trackPositions = settings.TrackSourcePosition;
            int  x;

            IAddChild blockParent = parent;

            while (block != null)
            {
                var       visitChildren = false;
                IAddChild lastParent    = null;

                switch (block.Tag)
                {
                case BlockTag.Document:
                    stackTight    = false;
                    visitChildren = true;
                    lastParent    = parent;
                    break;

                case BlockTag.Paragraph:
                    if (tight)
                    {
                        InlinesToXaml(blockParent, block.InlineContent, settings, inlineStack);
                    }
                    else
                    {
                        Paragraph paragraph = new Paragraph();
                        if (trackPositions)
                        {
                            PrintPosition(paragraph, block);
                        }
                        InlinesToXaml(paragraph, block.InlineContent, settings, inlineStack);
                        blockParent.AddChild(paragraph);
                    }
                    break;

                case BlockTag.BlockQuote:
                    Section blockquoteParagraph = new Section();
                    if (trackPositions)
                    {
                        PrintPosition(blockquoteParagraph, block);
                    }

                    if (QuoteStyle != null)
                    {
                        blockquoteParagraph.Style = QuoteStyle;
                    }

                    blockParent.AddChild(blockquoteParagraph);
                    lastParent  = blockParent;
                    blockParent = blockquoteParagraph;

                    stackTight    = true;
                    visitChildren = true;
                    break;

                case BlockTag.ListItem:

                    stackTight = tight;

                    if (block.ListData != null && block.ListData.ListType == ListType.TaskList)
                    {
                        BlockUIContainer ctnr = (BlockUIContainer)blockParent;
                        StackPanel       sp   = (StackPanel)ctnr.Child;

                        visitChildren = false;
                        TextBlock spcb = new TextBlock();
                        spcb.Style = TodoTextStyle;
                        Inline checkBoxInline = block.FirstChild?.InlineContent;
                        if (checkBoxInline != null)
                        {
                            InlinesToXaml(spcb, checkBoxInline, settings, inlineStack);
                        }

                        CheckBox bt = new CheckBox
                        {
                            IsChecked = block.TaskListItemIsChecked,
                            Content   = spcb,
                            Tag       = _checkBoxNumber
                        };
                        bt.CommandParameter = bt;
                        bt.Command          = CheckBoxCheckedCommand;
                        bt.Style            = TodoCheckBoxStyle;

                        sp.Children.Add(bt);

                        //TODO: Add child stack panel and add block.FirstChild.NextSibling

                        _checkBoxNumber++;
                    }
                    else
                    {
                        ListItem listItem = new ListItem();
                        if (ListItemStyle != null)
                        {
                            listItem.Style = ListItemStyle;
                        }

                        if (trackPositions)
                        {
                            PrintPosition(listItem, block);
                        }

                        blockParent.AddChild(listItem);

                        lastParent    = blockParent;
                        blockParent   = listItem;
                        visitChildren = true;
                    }

                    break;

                case BlockTag.List:
                    var       data = block.ListData;
                    IAddChild list;
                    if (data.ListType == ListType.TaskList)
                    {
                        StackPanel sp = new StackPanel();
                        list = new BlockUIContainer(sp);
                    }
                    else
                    {
                        List theList = new List();
                        list = theList;
                        theList.MarkerStyle = data.ListType == ListType.Bullet ? TextMarkerStyle.Disc : TextMarkerStyle.Decimal;

                        if (ListStyle != null)
                        {
                            theList.Style = ListStyle;
                        }
                    }

                    if (trackPositions)
                    {
                        PrintPosition((FrameworkContentElement)list, block);
                    }

                    // TODO: Check if first child starts with [ ] then it is a todo-list item
                    // TODO: Set list.StartIndex if > 1

                    blockParent.AddChild(list);
                    lastParent  = blockParent;
                    blockParent = list;

                    stackTight    = data.IsTight;
                    visitChildren = true;
                    break;

                case BlockTag.AtxHeading:
                case BlockTag.SetextHeading:
                    Paragraph headerParagraph = new Paragraph();
                    if (trackPositions)
                    {
                        PrintPosition(headerParagraph, block);
                    }

                    InlinesToXaml(headerParagraph, block.InlineContent, settings, inlineStack);

                    x = block.Heading.Level;

                    switch (x)
                    {
                    case 1:
                        headerParagraph.Style = Heading1Style;
                        break;

                    case 2:
                        headerParagraph.Style = Heading2Style;
                        break;

                    case 3:
                        headerParagraph.Style = Heading3Style;
                        break;

                    case 4:
                        headerParagraph.Style = Heading4Style;
                        break;

                    default:
                        headerParagraph.Style = Heading1Style;
                        break;
                    }

                    blockParent.AddChild(headerParagraph);

                    break;

                case BlockTag.IndentedCode:
                case BlockTag.FencedCode:
                    Paragraph codeblockParagraph = new Paragraph();

                    if (trackPositions)
                    {
                        PrintPosition(codeblockParagraph, block);
                    }

                    if (CodeBlockStyle != null)
                    {
                        codeblockParagraph.Style = CodeBlockStyle;
                    }

                    var info = block.FencedCodeData == null ? null : block.FencedCodeData.Info;
                    if (info != null && info.Length > 0)
                    {
                        //x = info.IndexOf(' ');
                        //if (x == -1)
                        //	x = info.Length;

                        //parent.WriteConstant(" class=\"language-");
                        //EscapeHtml(new StringPart(info, 0, x), parent);
                        //parent.Write('\"');
                    }

                    EscapeHtml(block.StringContent, codeblockParagraph);

                    blockParent.AddChild(codeblockParagraph);
                    break;

                case BlockTag.HtmlBlock:
                    // cannot output source position for HTML blocks
                    // block.StringContent.WriteTo(parent);

                    //TODO: Unable to convert html to

                    break;

                case BlockTag.ThematicBreak:
                    var line = new Line()
                    {
                        X2 = 1, StrokeThickness = 1.0
                    };
                    var container = new BlockUIContainer(line);
                    if (trackPositions)
                    {
                        PrintPosition(container, block);
                    }

                    if (LineStyle != null)
                    {
                        line.Style = LineStyle;
                    }

                    blockParent.AddChild(container);
                    break;

                case BlockTag.Table:
                    WriteTable(block, blockParent, settings, inlineStack);
                    break;

                case BlockTag.ReferenceDefinition:
                    break;

                default:
                    throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block);
                }

                if (visitChildren)
                {
                    stack.Push(new BlockStackEntry(lastParent, block.NextSibling, tight));

                    tight = stackTight;
                    block = block.FirstChild;
                }
                else if (block.NextSibling != null)
                {
                    block = block.NextSibling;
                }
                else
                {
                    block = null;
                }

                while (block == null && stack.Count > 0)
                {
                    var entry = stack.Pop();

                    blockParent = entry.Parent;
                    tight       = entry.IsTight;
                    block       = entry.Target;
                }
            }
        }
예제 #36
0
 internal static void PrintPosition(FrameworkContentElement writer, Block block)
 {
     writer.Tag = "DataSourcePos:" + block.SourcePosition.ToString(CultureInfo.InvariantCulture) + " - " + (block.SourcePosition + block.SourceLength).ToString(CultureInfo.InvariantCulture);
 }
예제 #37
0
 public BlockStackEntry(IAddChild parent, Block target, bool isTight)
 {
     Parent  = parent;
     Target  = target;
     IsTight = isTight;
 }
예제 #38
0
        /// <summary>
        /// Computes line number of a block in a page.
        /// </summary>
        /// <param name="block">The block to locate.</param>
        /// <param name="page">The page where the block is.</param>
        /// <returns>The block line.</returns>
        private int LocateBlockLine(Block block, Page page)
        {
            // Initialize the line to 1
            int line = 1;

            // Load the page until the block source position
            char[] buffer = new char[block.SourcePosition];
            string pagePath = this.fileSystem.FileInfo.FromFileName(page.FileSystemPath).FullName;
            using (StreamReader reader = new StreamReader(this.fileSystem.File.Open(pagePath, FileMode.Open, FileAccess.Read, FileShare.Read)))
            {
                reader.Read(buffer, 0, buffer.Length);
            }

            // Count the number of line break to increment line number
            foreach (char currentChar in buffer)
            {
                if ('\n' == currentChar)
                {
                    ++line;
                }
            }

            // Return the line number
            return line;
        }
예제 #39
0
        private static void BlockToDocumentBlock(CommonMark.Syntax.Block block, BlockCollection collection)
        {
            if (block == null)
            {
                return;
            }

            switch (block.Tag)
            {
            case BlockTag.Document:
                BlockToDocumentBlock(block.FirstChild, collection);
                break;

            case BlockTag.Paragraph:
                var paragraph = new Paragraph();

                CommonMark.Syntax.Inline current = block.InlineContent;
                while (current != null)
                {
                    var inline = InlineToDocumentInline(current);
                    if (inline != null)
                    {
                        paragraph.Inlines.Add(inline);
                    }

                    current = current.NextSibling;
                }

                collection.Add(paragraph);

                BlockToDocumentBlock(block.NextSibling, collection);
                break;

            case BlockTag.BlockQuote:
                var quoteBlock = new Section()
                {
                    Background = Brushes.LightGray, Margin = new Thickness(10)
                };
                collection.Add(quoteBlock);

                BlockToDocumentBlock(block.FirstChild, quoteBlock.Blocks);
                BlockToDocumentBlock(block.NextSibling, collection);
                break;

            case BlockTag.ListItem:
                throw new InvalidOperationException();

            case BlockTag.List:
                var listBlock = new List();
                collection.Add(listBlock);
                if (block.FirstChild != null)
                {
                    if (block.FirstChild.ListData.ListType == ListType.Ordered)
                    {
                        listBlock.MarkerStyle = TextMarkerStyle.Decimal;
                        listBlock.StartIndex  = block.FirstChild.ListData.Start;
                    }

                    BlockToDocumentBlock(block.FirstChild, listBlock.ListItems);
                }


                BlockToDocumentBlock(block.NextSibling, collection);
                break;

            case BlockTag.AtxHeading:
            case BlockTag.SetextHeading:
                var heading = GetHeadingItem(block.Heading.Level);


                heading.Inlines.Add(InlineToDocumentInline(block.InlineContent));
                collection.Add(heading);

                BlockToDocumentBlock(block.NextSibling, collection);
                break;

            case BlockTag.IndentedCode:
            case BlockTag.FencedCode:
                var codeBlock = new Section()
                {
                    Background = Brushes.LightGray, Margin = new Thickness(2)
                };
                collection.Add(codeBlock);
                var code = block.StringContent.TakeFromStart(block.StringContent.Length - 1);

                codeBlock.Blocks.Add(new Paragraph(new Run(code)
                {
                    FontFamily = new FontFamily("Courier New")
                }));

                BlockToDocumentBlock(block.NextSibling, collection);
                break;

            case BlockTag.HtmlBlock:
                // cannot output source position for HTML blocks
                //block.StringContent.WriteTo(writer);
                break;

            case BlockTag.ThematicBreak:
                var separator = new Rectangle();
                separator.Stroke          = new SolidColorBrush(Colors.LightGray);
                separator.StrokeThickness = 3;
                separator.Height          = 2;
                separator.Width           = double.NaN;

                var lineBlock = new BlockUIContainer(separator);
                collection.Add(lineBlock);

                BlockToDocumentBlock(block.NextSibling, collection);
                break;

            case BlockTag.ReferenceDefinition:

                break;

            default:
                throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="EnumeratorEntry"/> class.
 /// </summary>
 /// <param name="opening">Specifies if this instance represents the opening of the block element.</param>
 /// <param name="closing">Specifies if this instance represents the closing of the block element (returned by the
 /// enumerator after the children have been enumerated). Both <paramref name="closing"/> and <paramref name="opening"/>
 /// can be specified at the same time if there are no children for the <paramref name="block"/> element.</param>
 /// <param name="block">The block element being returned from the enumerator.</param>
 public EnumeratorEntry(bool opening, bool closing, Block block)
 {
     this.IsOpening = opening;
     this.IsClosing = closing;
     this.Block = block;
 }
예제 #41
0
        /// <summary>
        /// Writes the specified block element to the output stream. Does not write the child nodes, instead
        /// the <paramref name="ignoreChildNodes"/> is used to notify the caller whether it should recurse
        /// into the child nodes.
        /// </summary>
        /// <param name="block">The block element to be written to the output stream.</param>
        /// <param name="isOpening">Specifies whether the block element is being opened (or started).</param>
        /// <param name="isClosing">Specifies whether the block element is being closed. If the block does not
        /// have child nodes, then both <paramref name="isClosing"/> and <paramref name="isOpening"/> can be
        /// <see langword="true"/> at the same time.</param>
        /// <param name="ignoreChildNodes">Instructs the caller whether to skip processing of child nodes or not.</param>
        protected virtual void WriteBlock(Block block, bool isOpening, bool isClosing, out bool ignoreChildNodes)
        {
            ignoreChildNodes = false;
            int x;

            switch (block.Tag)
            {
                case BlockTag.Document:
                    break;

                case BlockTag.Paragraph:
                    if (RenderTightParagraphs.Peek())
                        break;

                    if (isOpening)
                    {
                        EnsureNewLine();
                        Write("<p");
                        if (Settings.TrackSourcePosition) WritePositionAttribute(block);
                        Write('>');
                    }

                    if (isClosing)
                        WriteLine("</p>");

                    break;

                case BlockTag.BlockQuote:
                    if (isOpening)
                    {
                        EnsureNewLine();
                        Write("<blockquote");
                        if (Settings.TrackSourcePosition) WritePositionAttribute(block);
                        WriteLine(">");

                        RenderTightParagraphs.Push(false);
                    }

                    if (isClosing)
                    {
                        RenderTightParagraphs.Pop();
                        WriteLine("</blockquote>");
                    }

                    break;

                case BlockTag.ListItem:
                    if (isOpening)
                    {
                        EnsureNewLine();
                        Write("<li");
                        if (Settings.TrackSourcePosition) WritePositionAttribute(block);
                        Write('>');
                    }

                    if (isClosing)
                        WriteLine("</li>");

                    break;

                case BlockTag.List:
                    var data = block.ListData;

                    if (isOpening)
                    {
                        EnsureNewLine();
                        Write(data.ListType == ListType.Bullet ? "<ul" : "<ol");
                        if (data.Start != 1)
                        {
                            Write(" start=\"");
                            Write(data.Start.ToString(CultureInfo.InvariantCulture));
                            Write('\"');
                        }
                        if (Settings.TrackSourcePosition) WritePositionAttribute(block);
                        WriteLine(">");

                        RenderTightParagraphs.Push(data.IsTight);
                    }

                    if (isClosing)
                    {
                        WriteLine(data.ListType == ListType.Bullet ? "</ul>" : "</ol>");
                        RenderTightParagraphs.Pop();
                    }

                    break;

                case BlockTag.AtxHeading:
                case BlockTag.SetextHeading:

                    x = block.Heading.Level;
                    if (isOpening)
                    {
                        EnsureNewLine();

                        Write("<h" + x.ToString(CultureInfo.InvariantCulture));
                        if (Settings.TrackSourcePosition)
                            WritePositionAttribute(block);

                        Write('>');
                    }

                    if (isClosing)
                        WriteLine("</h" + x.ToString(CultureInfo.InvariantCulture) + ">");

                    break;

                case BlockTag.IndentedCode:
                case BlockTag.FencedCode:

                    ignoreChildNodes = true;

                    EnsureNewLine();
                    Write("<pre><code");
                    if (Settings.TrackSourcePosition) WritePositionAttribute(block);

                    var info = block.FencedCodeData == null ? null : block.FencedCodeData.Info;
                    if (info != null && info.Length > 0)
                    {
                        x = info.IndexOf(' ');
                        if (x == -1)
                            x = info.Length;

                        Write(" class=\"language-");
                        WriteEncodedHtml(new StringPart(info, 0, x));
                        Write('\"');
                    }
                    Write('>');
                    WriteEncodedHtml(block.StringContent);
                    WriteLine("</code></pre>");
                    break;

                case BlockTag.HtmlBlock:
                    ignoreChildNodes = true;
                    // cannot output source position for HTML blocks
                    Write(block.StringContent);

                    break;

                case BlockTag.ThematicBreak:
                    ignoreChildNodes = true;
                    if (Settings.TrackSourcePosition)
                    {
                        Write("<hr");
                        WritePositionAttribute(block);
                        WriteLine();
                    }
                    else
                    {
                        WriteLine("<hr />");
                    }

                    break;

                case BlockTag.ReferenceDefinition:
                    break;

                default:
                    throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block);
            }

            if (ignoreChildNodes && !isClosing)
                throw new InvalidOperationException("Block of type " + block.Tag + " cannot contain child nodes.");
        }
예제 #42
0
 internal override async Task WriteStartIntroductionAsync(Block block)
 {
     await WriteStartElementAsync("glossary");
 }
예제 #43
0
        // Process one line at a time, modifying a block.
        // Returns 0 if successful.  curptr is changed to point to
        // the currently open block.
        public static void IncorporateLine(LineInfo line, ref Block curptr)
        {
            var ln = line.Line;

            Block last_matched_container;
            var offset = 0;
            int matched;
            int i;
            ListData data;
            bool all_matched = true;
            Block cur = curptr;
            bool blank = false;
            int first_nonspace;
            char curChar;
            int indent;

            // container starts at the document root.
            var container = cur.Top;

            // for each containing block, try to parse the associated line start.
            // bail out on failure:  container will point to the last matching block.

            while (container.LastChild != null && container.LastChild.IsOpen)
            {
                container = container.LastChild;

                first_nonspace = offset;
                while ((curChar = ln[first_nonspace]) == ' ')
                    first_nonspace++;

                indent = first_nonspace - offset;
                blank = curChar == '\n';

                switch (container.Tag)
                {
                    case BlockTag.BlockQuote:
                        {
                            if (indent <= 3 && curChar == '>')
                            {
                                offset = first_nonspace + 1;
                                if (ln[offset] == ' ')
                                    offset++;
                            }
                            else
                            {
                                all_matched = false;
                            }

                            break;
                        }

                    case BlockTag.ListItem:
                        {
                            if (indent >= container.ListData.MarkerOffset + container.ListData.Padding)
                                offset += container.ListData.MarkerOffset + container.ListData.Padding;
                            else if (blank)
                                offset = first_nonspace;
                            else
                                all_matched = false;

                            break;
                        }

                    case BlockTag.IndentedCode:
                        {
                            if (indent >= CODE_INDENT)
                                offset += CODE_INDENT;
                            else if (blank)
                                offset = first_nonspace;
                            else
                                all_matched = false;

                            break;
                        }

                    case BlockTag.AtxHeader:
                    case BlockTag.SETextHeader:
                        {
                            // a header can never contain more than one line
                            all_matched = false;
                            if (blank)
                                container.IsLastLineBlank = true;

                            break;
                        }

                    case BlockTag.FencedCode:
                        {
                            // -1 means we've seen closer 
                            if (container.FencedCodeData.FenceLength == -1)
                            {
                                all_matched = false;
                                if (blank)
                                    container.IsLastLineBlank = true;
                            }
                            else
                            {
                                // skip optional spaces of fence offset
                                i = container.FencedCodeData.FenceOffset;
                                while (i > 0 && ln[offset] == ' ')
                                {
                                    offset++;
                                    i--;
                                }
                            }

                            break;
                        }

                    case BlockTag.HtmlBlock:
                        {
                            if (blank)
                            {
                                container.IsLastLineBlank = true;
                                all_matched = false;
                            }

                            break;
                        }

                    case BlockTag.Paragraph:
                        {
                            if (blank)
                            {
                                container.IsLastLineBlank = true;
                                all_matched = false;
                            }

                            break;
                        }
                }

                if (!all_matched)
                {
                    container = container.Parent;  // back up to last matching block
                    break;
                }
            }

            last_matched_container = container;

            // check to see if we've hit 2nd blank line, break out of list:
            if (blank && container.IsLastLineBlank)
                BreakOutOfLists(ref container, line);

            var maybeLazy = cur.Tag == BlockTag.Paragraph;

            // unless last matched container is code block, try new container starts:
            while (container.Tag != BlockTag.FencedCode &&
                   container.Tag != BlockTag.IndentedCode &&
                   container.Tag != BlockTag.HtmlBlock)
            {

                first_nonspace = offset;
                while ((curChar = ln[first_nonspace]) == ' ')
                    first_nonspace++;

                indent = first_nonspace - offset;
                blank = curChar == '\n';
                var indented = indent >= CODE_INDENT;

                if (!indented && curChar == '>')
                {

                    offset = first_nonspace + 1;
                    // optional following character
                    if (ln[offset] == ' ')
                        offset++;

                    container = CreateChildBlock(container, line, BlockTag.BlockQuote, first_nonspace);

                }
                else if (!indented && curChar == '#' && 0 != (matched = Scanner.scan_atx_header_start(ln, first_nonspace, ln.Length, out i)))
                {

                    offset = first_nonspace + matched;
                    container = CreateChildBlock(container, line, BlockTag.AtxHeader, first_nonspace);
                    container.HeaderLevel = i;

                }
                else if (!indented && (curChar == '`' || curChar == '~') && 0 != (matched = Scanner.scan_open_code_fence(ln, first_nonspace, ln.Length)))
                {

                    container = CreateChildBlock(container, line, BlockTag.FencedCode, first_nonspace);
                    container.FencedCodeData = new FencedCodeData();
                    container.FencedCodeData.FenceChar = curChar;
                    container.FencedCodeData.FenceLength = matched;
                    container.FencedCodeData.FenceOffset = first_nonspace - offset;

                    offset = first_nonspace + matched;

                }
                else if (!indented && curChar == '<' && Scanner.scan_html_block_tag(ln, first_nonspace, ln.Length))
                {

                    container = CreateChildBlock(container, line, BlockTag.HtmlBlock, first_nonspace);
                    // note, we don't adjust offset because the tag is part of the text

                }
                else if (!indented && container.Tag == BlockTag.Paragraph && (curChar == '=' || curChar == '-')
                        && 0 != (matched = Scanner.scan_setext_header_line(ln, first_nonspace, ln.Length))
                        && ContainsSingleLine(container.StringContent))
                {

                    container.Tag = BlockTag.SETextHeader;
                    container.HeaderLevel = matched;
                    offset = ln.Length - 1;

                }
                else if (!indented 
                    && !(container.Tag == BlockTag.Paragraph && !all_matched) 
                    && 0 != (Scanner.scan_hrule(ln, first_nonspace, ln.Length)))
                {

                    // it's only now that we know the line is not part of a setext header:
                    container = CreateChildBlock(container, line, BlockTag.HorizontalRuler, first_nonspace);
                    Finalize(container, line);
                    container = container.Parent;
                    offset = ln.Length - 1;

                }
                else if ((!indented || container.Tag == BlockTag.List) 
                    && 0 != (matched = ParseListMarker(ln, first_nonspace, out data)))
                {

                    // compute padding:
                    offset = first_nonspace + matched;
                    i = 0;
                    while (i <= 5 && ln[offset + i] == ' ')
                        i++;

                    // i = number of spaces after marker, up to 5
                    if (i >= 5 || i < 1 || ln[offset] == '\n')
                    {
                        data.Padding = matched + 1;
                        if (i > 0)
                            offset++;
                    }
                    else
                    {
                        data.Padding = matched + i;
                        offset += i;
                    }

                    // check container; if it's a list, see if this list item
                    // can continue the list; otherwise, create a list container.

                    data.MarkerOffset = indent;

                    if (container.Tag != BlockTag.List || !ListsMatch(container.ListData, data))
                    {
                        container = CreateChildBlock(container, line, BlockTag.List, first_nonspace);
                        container.ListData = data;
                    }

                    // add the list item
                    container = CreateChildBlock(container, line, BlockTag.ListItem, first_nonspace);
                    container.ListData = data;
                }
                else if (indented && !maybeLazy && !blank)
                {
                    offset += CODE_INDENT;
                    container = CreateChildBlock(container, line, BlockTag.IndentedCode, offset);
                }
                else
                {
                    break;
                }

                if (AcceptsLines(container.Tag))
                {
                    // if it's a line container, it can't contain other containers
                    break;
                }

                maybeLazy = false;
            }

            // what remains at offset is a text line.  add the text to the
            // appropriate container.

            first_nonspace = offset;
            if (offset >= ln.Length)
                curChar = '\0';
            else
                while ((curChar = ln[first_nonspace]) == ' ')
                    first_nonspace++;

            indent = first_nonspace - offset;
            blank = curChar == '\n';

            // block quote lines are never blank as they start with >
            // and we don't count blanks in fenced code for purposes of tight/loose
            // lists or breaking out of lists.  we also don't set last_line_blank
            // on an empty list item.
            container.IsLastLineBlank = (blank &&
                                          container.Tag != BlockTag.BlockQuote &&
                                          container.Tag != BlockTag.SETextHeader &&
                                          container.Tag != BlockTag.FencedCode &&
                                          !(container.Tag == BlockTag.ListItem &&
                                            container.FirstChild == null &&
                                            container.SourcePosition >= line.LineOffset));

            Block cont = container;
            while (cont.Parent != null)
            {
                cont.Parent.IsLastLineBlank = false;
                cont = cont.Parent;
            }

            if (cur != last_matched_container &&
                container == last_matched_container &&
                !blank &&
                cur.Tag == BlockTag.Paragraph &&
                cur.StringContent.Length > 0)
            {

                AddLine(cur, line, ln, offset);

            }
            else
            { // not a lazy continuation

                // finalize any blocks that were not matched and set cur to container:
                while (cur != last_matched_container)
                {

                    Finalize(cur, line);
                    cur = cur.Parent;

                    if (cur == null)
                        throw new CommonMarkException("Cannot finalize container block. Last matched container tag = " + last_matched_container.Tag);

                }

                if (container.Tag == BlockTag.IndentedCode)
                {

                    AddLine(container, line, ln, offset);

                }
                else if (container.Tag == BlockTag.FencedCode)
                {

                    if ((indent <= 3
                      && curChar == container.FencedCodeData.FenceChar)
                      && (0 != Scanner.scan_close_code_fence(ln, first_nonspace, container.FencedCodeData.FenceLength, ln.Length)))
                    {
                        // if closing fence, set fence length to -1. it will be closed when the next line is processed. 
                        container.FencedCodeData.FenceLength = -1;
                    }
                    else
                    {
                        AddLine(container, line, ln, offset);
                    }

                }
                else if (container.Tag == BlockTag.HtmlBlock)
                {

                    AddLine(container, line, ln, offset);

                }
                else if (blank)
                {

                    // ??? do nothing

                }
                else if (container.Tag == BlockTag.AtxHeader)
                {

                    int p = ln.Length - 1;

                    // trim trailing spaces
                    while (p >= 0 && (ln[p] == ' ' || ln[p] == '\n'))
                        p--;

                    // if string ends in #s, remove these:
                    while (p >= 0 && ln[p] == '#')
                        p--;

                    // there must be a space before the last hashtag
                    if (p < 0 || ln[p] != ' ')
                        p = ln.Length - 1;

                    AddLine(container, line, ln, first_nonspace, p - first_nonspace + 1);
                    Finalize(container, line);
                    container = container.Parent;

                }
                else if (AcceptsLines(container.Tag))
                {

                    AddLine(container, line, ln, first_nonspace);

                }
                else if (container.Tag != BlockTag.HorizontalRuler && container.Tag != BlockTag.SETextHeader)
                {

                    // create paragraph container for line
                    container = CreateChildBlock(container, line, BlockTag.Paragraph,  first_nonspace);
                    AddLine(container, line, ln, first_nonspace);

                }
                else
                {

                    Utilities.Warning("Line {0} with container type {1} did not match any condition:\n\"{2}\"", line.LineNumber, container.Tag, ln);

                }

                curptr = container;
            }
        }
예제 #44
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;
#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;
        }
예제 #45
0
 /// <summary>Initializes a new instance of the <see cref="CommonMarkException" /> class with a specified error message, a reference to the element that caused it and a reference to the inner exception that is the cause of this exception.</summary>
 /// <param name="message">The error message that explains the reason for the exception.</param>
 /// <param name="block">The block element that is related to the exception cause.</param>
 /// <param name="innerException">The exception that is the cause of the current exception, or a <c>null</c> reference (<c>Nothing</c> in Visual Basic) if no inner exception is specified.</param>
 public CommonMarkException(string message, Block block, Exception innerException = null)
     : base(message, innerException) 
 {
     this.BlockElement = block;
 }