Exemplo n.º 1
0
        public MarkdownQuoteBlock(QuoteBlock quoteBlock)
        {
            this.quoteBlock = quoteBlock;

            AutoSizeAxes     = Axes.Y;
            RelativeSizeAxes = Axes.X;
        }
Exemplo n.º 2
0
        public void QuoteBlockNoTitle()
        {
            var block = new QuoteBlock();
            var title = block.GetTitle();

            Assert.Equal("Empty", title);
        }
        /// <summary>
        /// Renders a quote element.
        /// </summary>
        protected override void RenderQuote(QuoteBlock element, IRenderContext context)
        {
            if (!(context is BlockCollectionRenderContext localContext))
            {
                throw new RenderContextIncorrectException();
            }

            var blockCollection = localContext.BlockCollection;

            var section = new Section
            {
                Margin          = QuoteMargin,
                Background      = QuoteBackground,
                BorderThickness = QuoteBorderThickness,
                Padding         = QuotePadding,
            };

            var childContext = new BlockCollectionRenderContext(section.Blocks, context)
            {
                Parent = section
            };

            if (QuoteForeground != null && !localContext.OverrideForeground)
            {
                childContext.Foreground = QuoteForeground;
            }

            RenderBlocks(element.Blocks, childContext);

            section.BorderBrush = childContext.OverrideForeground ? childContext.Foreground : QuoteBorderBrush ?? childContext.Foreground;

            blockCollection.Add(section);
        }
        /// <summary>
        /// Renders a quote element.
        /// </summary>
        protected override void RenderQuote(QuoteBlock element, IRenderContext context)
        {
            if (!(context is UIElementCollectionRenderContext localContext))
            {
                throw new RenderContextIncorrectException();
            }

            var blockUIElementCollection = localContext.BlockUIElementCollection;

            var stackPanel   = new StackPanel();
            var childContext = new UIElementCollectionRenderContext(stackPanel.Children, context)
            {
                Parent = stackPanel
            };

            if (QuoteForeground != null && !localContext.OverrideForeground)
            {
                childContext.Foreground = QuoteForeground;
            }

            RenderBlocks(element.Blocks, childContext);

            var border = new Border
            {
                Margin          = QuoteMargin,
                Background      = QuoteBackground,
                BorderBrush     = childContext.OverrideForeground ? childContext.Foreground : QuoteBorderBrush ?? childContext.Foreground,
                BorderThickness = QuoteBorderThickness,
                Padding         = QuotePadding,
                Child           = stackPanel
            };

            blockUIElementCollection.Add(border);
        }
Exemplo n.º 5
0
        public async Task <IActionResult> Quote(Enumeration.ContentItemType contentType, int contentId)
        {
            var block = new QuoteBlock();

            SetTypeId(block, contentType, contentId);
            block.LastModified = block.Date = DateTime.UtcNow;
            await _blockRepository.Create(block);

            return(ViewComponent("Block", block));
        }
Exemplo n.º 6
0
        public void QuoteBlockHasTitle()
        {
            var block = new QuoteBlock()
            {
                Body = new Extend.Fields.TextField
                {
                    Value = "To be or not to be"
                }
            };
            var title = block.GetTitle();

            Assert.Equal("To be or not to be", title);
        }
Exemplo n.º 7
0
        public void SearchQuoteBlock()
        {
            var block = new QuoteBlock
            {
                Body = new TextField
                {
                    Value = "Lorem ipsum"
                }
            };
            var search = block.GetIndexedContent();

            Assert.Equal(block.Body.Value, search);
        }
        /// <summary>
        /// Renders a quote element.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="currentBlocks"></param>
        private void RenderQuote(QuoteBlock element, BlockCollection currentBlocks)
        {
            // Make the new quote paragraph
            Paragraph quotePara = new Paragraph();

            quotePara.Margin     = new Thickness(element.QuoteIndent * 12, 12, 12, 12);
            quotePara.Foreground = new SolidColorBrush(Color.FromArgb(180, 255, 255, 255));

            // Add it to the blocks
            currentBlocks.Add(quotePara);

            // Render the children into the para inline.
            bool trimTextStart = true;

            RenderInlineChildren(element, quotePara.Inlines, ref trimTextStart);
        }
Exemplo n.º 9
0
        public void Setup()
        {
            document = new Document();
            // Workaround for a quirk in the migradoc API.
            _          = document.AddSection().Elements;
            pdfBuilder = new PdfBuilder(document, PdfOptions.Default);
            renderer   = new QuoteBlockRenderer();

            // Setup the sample quote block.
            quote     = new QuoteBlock(new QuoteBlockParser());
            quoteText = "some text";
            ParagraphBlock paragraph = new ParagraphBlock(new ParagraphBlockParser());

            paragraph.Inline = new ContainerInline().AppendChild(new LiteralInline(quoteText));
            quote.Add(paragraph);
        }
Exemplo n.º 10
0
        private View Render(QuoteBlock block)
        {
            var blockQuote = BlockQuoteTemplate.CreateContent() as View;

            var inner = new StackLayout();

            foreach (var view in RenderBlocks(block.AsEnumerable()))
            {
                inner.Children.Add(view);
            }

            blockQuote.BindingContext = new Templates.BlockQuoteAstNode
            {
                View = inner
            };

            return(blockQuote);
        }
Exemplo n.º 11
0
        private IEnumerable <View> Render(QuoteBlock block)
        {
            var initialIsQuoted = this.isQuoted;
            //var initialStack = this.stack;
            var views = new List <View>();

            this.isQuoted = true;
            var stack = new StackLayout()
            {
                Spacing = this.Theme.Margin,
            };

            var style = this.Theme.Quote;

            if (style.BorderSize > 0)
            {
                var horizontalStack = new StackLayout()
                {
                    Orientation     = StackOrientation.Horizontal,
                    BackgroundColor = this.Theme.Quote.BackgroundColor,
                };

                horizontalStack.Children.Add(new BoxView()
                {
                    WidthRequest    = style.BorderSize,
                    BackgroundColor = style.BorderColor,
                });

                horizontalStack.Children.Add(stack);
                views.Add(horizontalStack);
            }
            else
            {
                stack.BackgroundColor = this.Theme.Quote.BackgroundColor;
                views.Add(stack);
            }

            var subviews = this.Render(block.AsEnumerable());

            this.isQuoted = initialIsQuoted;
            //this.stack = initialStack;
            return(subviews);
        }
Exemplo n.º 12
0
        private OpenXmlElement[] ConvertQuoteBlock(QuoteBlock quoteBlock, int numberingId, int nestLevel)
        {
            var styleId = UserSettingStyleMap.GetStyleId(UserSettingStyleMap.StyleMapKeyType.Quote, null);

            var oxmlElements = new List <OpenXmlElement>();

            foreach (var block in quoteBlock)
            {
                switch (block)
                {
                case ParagraphBlock paragraphBlock:
                    var oxmlParagraph      = ConvertParagraphBlock(paragraphBlock, WordDocumentNumberingManager.OutsideOfListNumberingId, 0);
                    var oxmlQuoteParagraph = Manipulator.ElementCreator.CreateQuoteElement(oxmlParagraph, styleId, numberingId, nestLevel);

                    Manipulator.AdjustImageDimension(oxmlQuoteParagraph);

                    oxmlElements.Add(oxmlQuoteParagraph);
                    break;

                case ListBlock listBlock:
                    var oxmlListItems = ConvertListBlock(listBlock, WordDocumentNumberingManager.OutsideOfListNumberingId, 0);
                    foreach (var oxmlListItem in oxmlListItems)
                    {
                        if (oxmlListItem.GetType() == typeof(Paragraph))
                        {
                            var oxmlListItemParagraph      = (Paragraph)oxmlListItem;
                            var oxmlListItemQuoteParagraph = Manipulator.ElementCreator.CreateQuoteElement(oxmlListItemParagraph, styleId, numberingId, nestLevel);

                            Manipulator.AdjustImageDimension(oxmlListItemQuoteParagraph);

                            oxmlElements.Add(oxmlListItemQuoteParagraph);
                        }
                    }
                    break;

                default:
                    throw new NotImplementedException(string.Format("Unknown block type within the quote block: {0}", block.GetType().FullName));
                }
            }

            return(oxmlElements.ToArray());
        }
Exemplo n.º 13
0
        /// <summary>
        /// Called by all elements to find the next element to parse out of the markdown given a startingPos and an ending Pos
        /// </summary>
        /// <param name="markdown"></param>
        /// <param name="startingPos"></param>
        /// <param name="endingPost"></param>
        /// <returns></returns>
        public static MarkdownBlock FindNextBlock(ref string markdown, ref int startingPos, int endingPos)
        {
            // We need to look at the start of this current block and figure out what type it is.
            // Find the next char that isn't a \n, \r, or ' ', keep track of white space
            int spaceCount = 0;

            while (markdown.Length > startingPos && endingPos > startingPos && (markdown[startingPos] == '\r' || markdown[startingPos] == '\n' || Char.IsWhiteSpace(markdown[startingPos])))
            {
                // If we find a space count it for the indent rules. If not reset the count.
                spaceCount = markdown[startingPos] == ' ' ? spaceCount + 1 : 0;
                startingPos++;
            }

            if (CodeBlock.CanHandleBlock(ref markdown, startingPos, endingPos, spaceCount))
            {
                return(new CodeBlock());
            }
            if (QuoteBlock.CanHandleBlock(ref markdown, startingPos, endingPos))
            {
                return(new QuoteBlock());
            }
            if (HeaderBlock.CanHandleBlock(ref markdown, startingPos, endingPos))
            {
                return(new HeaderBlock());
            }
            if (ListElementBlock.CanHandleBlock(ref markdown, startingPos, endingPos))
            {
                return(new ListElementBlock());
            }
            if (HorizontalRuleBlock.CanHandleBlock(ref markdown, startingPos, endingPos))
            {
                return(new HorizontalRuleBlock());
            }
            if (LineBreakBlock.CanHandleBlock(ref markdown, startingPos, endingPos))
            {
                return(new LineBreakBlock());
            }

            // If we can't match any of these just make a new paragraph.
            return(new ParagraphBlock());
        }
Exemplo n.º 14
0
        private void Render(QuoteBlock block)
        {
            var initialIsQuoted = this.isQuoted;
            var initialStack    = this.stack;

            this.isQuoted = true;
            this.stack    = new StackLayout()
            {
                Spacing = this.Theme.Margin,
            };

            var style = this.Theme.Quote;

            if (style.BorderSize > 0)
            {
                var horizontalStack = new StackLayout()
                {
                    Orientation     = StackOrientation.Horizontal,
                    BackgroundColor = this.Theme.Quote.BackgroundColor,
                };

                horizontalStack.Children.Add(new BoxView()
                {
                    WidthRequest    = style.BorderSize,
                    BackgroundColor = style.BorderColor,
                });

                horizontalStack.Children.Add(this.stack);
                initialStack.Children.Add(horizontalStack);
            }
            else
            {
                stack.BackgroundColor = this.Theme.Quote.BackgroundColor;
                initialStack.Children.Add(this.stack);
            }

            this.Render(block.AsEnumerable());

            this.isQuoted = initialIsQuoted;
            this.stack    = initialStack;
        }
Exemplo n.º 15
0
        void Render(QuoteBlock block)
        {
            var initialIsQuoted = isQuoted;
            var initialStack    = stack;

            isQuoted = true;
            stack    = new StackLayout()
            {
                Spacing = Theme.VerticalSpacing,
            };

            var style = Theme.Quote;

            if (style.BorderSize > 0)
            {
                var horizontalStack = new StackLayout()
                {
                    Orientation     = StackOrientation.Horizontal,
                    BackgroundColor = Theme.Quote.BackgroundColor,
                };

                horizontalStack.Children.Add(new BoxView()
                {
                    WidthRequest    = style.BorderSize,
                    BackgroundColor = style.BorderColor,
                });

                horizontalStack.Children.Add(stack);
                initialStack.Children.Add(horizontalStack);
            }
            else
            {
                stack.BackgroundColor = Theme.Quote.BackgroundColor;
                initialStack.Children.Add(stack);
            }

            Render(block.AsEnumerable());

            isQuoted = initialIsQuoted;
            stack    = initialStack;
        }
Exemplo n.º 16
0
        /// <summary>
        /// Renders a quote element.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="blockUIElementCollection"></param>
        private void RenderQuote(QuoteBlock element, UIElementCollection blockUIElementCollection, RenderContext context)
        {
            if (QuoteForeground != null)
            {
                context            = context.Clone();
                context.Foreground = QuoteForeground;
            }

            var stackPanel = new StackPanel();

            RenderBlocks(element.Blocks, stackPanel.Children, context);

            var border = new Border();

            border.Margin          = QuoteMargin;
            border.Background      = QuoteBackground;
            border.BorderBrush     = QuoteBorderBrush ?? context.Foreground;
            border.BorderThickness = QuoteBorderThickness;
            border.Padding         = QuotePadding;
            border.Child           = stackPanel;

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

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

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

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

                        nonSpacePos++;
                    }

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

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

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

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

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

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

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

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

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

                        return(blocks);
                    }
                }

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

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

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

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

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

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

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

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

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

                        blocks.Add(newBlockElement);
                    }
                }

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

            actualEnd = startOfLine;
            return(blocks);
        }
Exemplo n.º 18
0
        public override BlockState TryOpen(BlockProcessor processor)
        {
            if (processor.IsCodeIndent)
            {
                return(BlockState.None);
            }

            var column         = processor.Column;
            var sourcePosition = processor.Start;

            // 5.1 Block quotes
            // A block quote marker consists of 0-3 spaces of initial indent, plus
            // (a) the character > together with a following space, or
            // (b) a single character > not followed by a space.
            // (c) a single character > followed by a space and explanation mark
            // denoting the css class to apply to the block quote
            // i.e....
            // > !danger This is a dangerous quote
            // > !success This is a success quote

            var currentChar = processor.CurrentChar;
            var c           = processor.NextChar();

            if (c.IsSpaceOrTab())
            {
                c = processor.NextChar();
            }

            var cssClass = "";

            if (c == '!')
            {
                // Parse until we reach white space
                while (true)
                {
                    if (c.IsWhitespace())
                    {
                        break;
                    }
                    c = processor.NextChar();
                    if (!c.IsWhitespace())
                    {
                        cssClass += c;
                    }
                }
            }

            if (c.IsSpaceOrTab())
            {
                processor.NextColumn();
            }

            // Build quote
            var quoteBlock = new QuoteBlock(this)
            {
                QuoteChar = currentChar,
                Column    = column,
                Span      = new SourceSpan(sourcePosition, processor.Line.End),
            };

            // If we found a css class ensure it's allowed
            if (!string.IsNullOrEmpty(cssClass))
            {
                var validCss = cssClass.ToLower();
                if (_validCssClasses.Contains(validCss))
                {
                    quoteBlock.GetAttributes().AddClass(validCss);
                }
            }

            processor.NewBlocks.Push(quoteBlock);

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

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

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

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

                        nonSpacePos++;
                    }

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

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

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

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

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

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

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

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

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

                        return(blocks);
                    }
                }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        blocks.Add(newBlockElement);
                    }
                }

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

            actualEnd = startOfLine;
            return(blocks);
        }
 /// <summary>
 /// Renders a quote element.
 /// </summary>
 /// <param name="element"> The parsed block element to render. </param>
 /// <param name="context"> Persistent state. </param>
 protected abstract void RenderQuote(QuoteBlock element, IRenderContext context);
Exemplo n.º 21
0
        public override BlockState TryOpen(BlockProcessor processor)
        {
            if (processor.IsCodeIndent)
            {
                return(BlockState.None);
            }

            var sourcePosition = processor.Start;

            // 5.1 Block quotes
            // A block quote marker consists of 0-3 spaces of initial indent, plus (a) the character > together with a following space, or (b) a single character > not followed by a space.
            var quoteChar = processor.CurrentChar;
            var column    = processor.Column;
            var c         = processor.NextChar();

            var quoteBlock = new QuoteBlock(this)
            {
                QuoteChar   = quoteChar,
                Column      = column,
                Span        = new SourceSpan(sourcePosition, processor.Line.End),
                LinesBefore = processor.UseLinesBefore()
            };

            bool hasSpaceAfterQuoteChar = false;

            if (c == ' ')
            {
                processor.NextColumn();
                hasSpaceAfterQuoteChar         = true;
                processor.SkipFirstUnwindSpace = true;
            }
            else if (c == '\t')
            {
                processor.NextColumn();
            }

            var         triviaBefore = processor.UseTrivia(sourcePosition - 1);
            StringSlice triviaAfter  = StringSlice.Empty;
            bool        wasEmptyLine = false;

            if (processor.Line.IsEmptyOrWhitespace())
            {
                processor.TriviaStart = processor.Start;
                triviaAfter           = processor.UseTrivia(processor.Line.End);
                wasEmptyLine          = true;
            }
            quoteBlock.QuoteLines.Add(new QuoteBlockLine
            {
                TriviaBefore           = triviaBefore,
                TriviaAfter            = triviaAfter,
                QuoteChar              = true,
                HasSpaceAfterQuoteChar = hasSpaceAfterQuoteChar,
                NewLine = processor.Line.NewLine,
            });
            processor.NewBlocks.Push(quoteBlock);
            if (!wasEmptyLine)
            {
                processor.TriviaStart = processor.Start;
            }
            return(BlockState.Continue);
        }
Exemplo n.º 22
0
        /// <summary>
        /// Adds DocFX Note Support on top of Quote Formatting.
        /// </summary>
        /// <param name="element">QuoteBlock Element</param>
        /// <param name="context">Render Context</param>
        protected override void RenderQuote(QuoteBlock element, IRenderContext context)
        {
            // Grab the Local context and cast it.
            var localContext = context as UIElementCollectionRenderContext;
            var collection   = localContext?.BlockUIElementCollection;

            // Store these, they will be changed temporarily.
            var originalQuoteForeground = QuoteForeground;
            var originalLinkForeground  = LinkForeground;

            DocFXNote       noteType        = null;
            string          header          = null;
            SolidColorBrush localforeground = null;
            SolidColorBrush localbackground = null;
            string          symbolglyph     = string.Empty;

            // Check the required structure of the Quote is correct. Determine if it is a DocFX Note.
            if (element.Blocks.First() is ParagraphBlock para)
            {
                if (para.Inlines.First() is TextRunInline textinline)
                {
                    // Find the matching DocFX note style and header.
                    foreach (var style in styles)
                    {
                        // Search between stylisticly matching notes with different headers.
                        foreach (var identifier in style.Identifiers)
                        {
                            // Match the identifier with the start of the Quote to match.
                            if (textinline.Text.StartsWith(identifier.Key))
                            {
                                noteType    = style;
                                header      = identifier.Value;
                                symbolglyph = style.Glyph;

                                // Removes the identifier from the text
                                textinline.Text = textinline.Text.Replace(identifier.Key, string.Empty);

                                localforeground = style.LightForeground;
                                localbackground = style.LightBackground;
                            }
                        }
                    }

                    // Apply special formatting context.
                    if (noteType != null)
                    {
                        if (localContext?.Clone() is UIElementCollectionRenderContext newcontext)
                        {
                            localContext = newcontext;

                            localContext.TrimLeadingWhitespace = true;
                            QuoteForeground = Foreground;
                            LinkForeground  = localforeground;
                        }
                    }
                }
            }

            // Begins the standard rendering.
            base.RenderQuote(element, localContext);

            // Add styling to render if DocFX note.
            if (noteType != null)
            {
                // Restore original formatting properties.
                QuoteForeground = originalQuoteForeground;
                LinkForeground  = originalLinkForeground;

                if (localContext == null || collection?.Any() != true)
                {
                    return;
                }

                // Gets the current Quote Block UI from the UI Collection, and then styles it. Adds a header.
                if (collection.Last() is Border border)
                {
                    border.CornerRadius    = new CornerRadius(6);
                    border.BorderThickness = new Thickness(0);
                    border.Padding         = new Thickness(20);
                    border.Margin          = new Thickness(0, 5, 0, 5);
                    border.Background      = localbackground;

                    var headerPanel = new StackPanel
                    {
                        Orientation = Orientation.Horizontal,
                        Margin      = new Thickness(0, 0, 0, 10)
                    };

                    headerPanel.Children.Add(new TextBlock
                    {
                        FontSize   = 18,
                        Foreground = localforeground,
                        Text       = symbolglyph,
                        FontFamily = new FontFamily("Segoe MDL2 Assets"),
                    });

                    headerPanel.Children.Add(new TextBlock
                    {
                        FontSize          = 16,
                        Foreground        = localforeground,
                        Margin            = new Thickness(5, 0, 0, 0),
                        Text              = header,
                        VerticalAlignment = VerticalAlignment.Center,
                        TextLineBounds    = TextLineBounds.Tight,
                        FontWeight        = FontWeights.SemiBold
                    });

                    if (border.Child is StackPanel panel)
                    {
                        panel.Children.Insert(0, headerPanel);
                    }
                }
            }
        }
Exemplo n.º 23
0
 protected override void RenderQuote(QuoteBlock element, IRenderContext context)
 {
 }
Exemplo n.º 24
0
 protected override MarkdownQuoteBlock CreateQuoteBlock(QuoteBlock quoteBlock) => new OsuMarkdownQuoteBlock(quoteBlock);
Exemplo n.º 25
0
 public OsuMarkdownQuoteBlock(QuoteBlock quoteBlock)
     : base(quoteBlock)
 {
 }
 public MarkdownQuoteBlock(QuoteBlock quoteBlock) : this()
 {
     Style = quoteBlock;
 }
 protected override void RenderQuote(QuoteBlock element, IRenderContext context)
 {
     throw new NotImplementedException();
 }