Пример #1
0
        /// <summary>
        /// Convert a Markdown element to a Forkdown one.
        /// </summary>
        /// <param name="mdo">Markdown object to convert.</param>
        public static Element ToForkdown(IMarkdownObject mdo)
        {
            Element result = mdo switch {
                MarkdownDocument _ => new Document(),
                HeadingBlock h => new Heading(h),
                ListBlock l => new Listing(l),
                ListItemBlock li => new ListItem(li),
                ParagraphBlock p => new Paragraph(p),
                CustomContainer c => new Section(c),
                CustomContainerInline c => new ExplicitInlineContainer(c),
                CodeInline c => new Code(c),
                FencedCodeBlock c => new CodeBlock(c),
                LinkInline l => new Link(l),
                LiteralInline t => new Text(t),
                LineBreakInline _ => new LineBreak(),
                ThematicBreakBlock _ => new Separator(),
                Tables.Table t => new Table(t),
                Tables.TableRow tr => new TableRow(tr),
                Tables.TableCell tc => new TableCell(tc),
                EmphasisInline e => new Emphasis(e),
                HtmlBlock b => new Html(b),
                _ => new Placeholder(mdo),
            };

            var subs = mdo switch {
                LeafBlock b => b.Inline,
                IEnumerable <MarkdownObject> e => e,
                _ => null
            } ?? Nil.E <MarkdownObject>();
        public void Heading_should_construct_from_HeadingBlock_correctly()
        {
            var headingBlock = new HeadingBlock(new ParagraphBlockParser());

            headingBlock.Inline = new ContainerInline();

            var firstContent = new LiteralInline("myheading");

            headingBlock.Inline.AppendChild(firstContent);

            var firstHeading = new Heading(headingBlock);

            Assert.AreEqual("myheading", firstHeading.Title);

            var secondContent = new LiteralInline("-myotherheading");

            headingBlock.Inline.AppendChild(secondContent);

            var secondHeading = new Heading(headingBlock);

            Assert.AreEqual("myheading-myotherheading", secondHeading.Title);

            var codeContent = new CodeInline();

            codeContent.Content = "awesomeclassname";
            headingBlock.Inline.AppendChild(codeContent);

            var codeHeading = new Heading(headingBlock);

            Assert.AreEqual("myheading-myotherheadingawesomeclassname", codeHeading.Title);
        }
Пример #3
0
        /// <summary>
        /// Renders a code element
        /// </summary>
        /// <param name="inlineCollection"> The list to add to. </param>
        /// <param name="element"> The parsed inline element to render. </param>
        /// <param name="parent"> The container element. </param>
        /// <param name="context"> Persistent state. </param>
        private void RenderCodeRun(InlineCollection inlineCollection, CodeInline element, TextElement parent, RenderContext context)
        {
            var run = new Run();

            run.FontFamily = CodeFontFamily ?? FontFamily;
            run.Text       = CollapseWhitespace(context, element.Text);

            // Add it to the current inlines
            inlineCollection.Add(run);
        }
Пример #4
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 CodeInlineRenderer();
     inline         = new CodeInline();
     inline.Content = sampleCode = "sample code";
 }
        /// <summary>
        /// Renders a code element
        /// </summary>
        /// <param name="element"> The parsed inline element to render. </param>
        /// <param name="context"> Persistent state. </param>
        protected override void RenderCodeRun(CodeInline element, IRenderContext context)
        {
            var localContext = context as InlineRenderContext;

            if (localContext == null)
            {
                throw new RenderContextIncorrectException();
            }

            var text = CreateTextBlock(localContext);

            text.Text       = CollapseWhitespace(context, element.Text);
            text.FontFamily = InlineCodeFontFamily ?? FontFamily;

            if (localContext.WithinItalics)
            {
                text.FontStyle = FontStyle.Italic;
            }

            if (localContext.WithinBold)
            {
                text.FontWeight = FontWeights.Bold;
            }

            var borderthickness = InlineCodeBorderThickness;
            var padding         = InlineCodePadding;
            var spacingoffset   = -(borderthickness.Bottom + padding.Bottom);

            var margin = new Thickness(0, spacingoffset, 0, spacingoffset);

            var border = new Border
            {
                BorderThickness = borderthickness,
                BorderBrush     = InlineCodeBorderBrush,
                Background      = InlineCodeBackground,
                Child           = text,
                Padding         = padding,
                Margin          = margin
            };

            // Aligns content in InlineUI, see https://social.msdn.microsoft.com/Forums/silverlight/en-US/48b5e91e-efc5-4768-8eaf-f897849fcf0b/richtextbox-inlineuicontainer-vertical-alignment-issue?forum=silverlightarchieve
            border.RenderTransform = new TranslateTransform
            {
                Y = 4
            };

            var inlineUIContainer = new InlineUIContainer
            {
                Child = border,
            };

            // Add it to the current inlines
            localContext.InlineCollection.Add(inlineUIContainer);
        }
Пример #6
0
        static Common()
        {
            BoldTextInline.AddTripChars(_triggerList);
            ItalicTextInline.AddTripChars(_triggerList);
            MarkdownLinkInline.AddTripChars(_triggerList);
            HyperlinkInline.AddTripChars(_triggerList);
            StrikethroughTextInline.AddTripChars(_triggerList);
            SuperscriptTextInline.AddTripChars(_triggerList);
            CodeInline.AddTripChars(_triggerList);

            // Create an array of characters to search against using IndexOfAny.
            _tripCharacters = _triggerList.Select(trigger => trigger.FirstChar).Distinct().ToArray();
        }
Пример #7
0
        /// <summary>
        /// Renders a code element.
        /// </summary>
        /// <param name="inlineCollection"> The list to add to. </param>
        /// <param name="element"> The parsed inline element to render. </param>
        /// <param name="context"> Persistent state. </param>
        private void RenderCodeRun(InlineCollection inlineCollection, CodeInline element, RenderContext context)
        {
            var color = ((SolidColorBrush)Foreground).Color;

            color.A = 160;
            var run = new Run
            {
                FontFamily = CodeFontFamily ?? FontFamily,
                Text       = CollapseWhitespace(context, element.Text),
                Foreground = new SolidColorBrush(color),
            };

            // Add it to the current inlines
            inlineCollection.Add(run);
        }
Пример #8
0
        /// <summary>
        /// Renders a code element
        /// </summary>
        /// <param name="element"> The parsed inline element to render. </param>
        /// <param name="context"> Persistent state. </param>
        protected override void RenderCodeRun(CodeInline element, IRenderContext context)
        {
            if (!(context is InlineRenderContext localContext))
            {
                throw new RenderContextIncorrectException();
            }

            var text = CreateTextBlock(localContext);

            text.Text       = CollapseWhitespace(context, element.Text);
            text.FontFamily = InlineCodeFontFamily ?? FontFamily;
            text.Foreground = InlineCodeForeground ?? Foreground;

            if (localContext.WithinItalics)
            {
                text.FontStyle = FontStyles.Italic;
            }

            if (localContext.WithinBold)
            {
                text.FontWeight = FontWeights.Bold;
            }

            var border = new Border
            {
                BorderThickness = InlineCodeBorderThickness,
                BorderBrush     = InlineCodeBorderBrush,
                Background      = InlineCodeBackground,
                Child           = text,
                Padding         = InlineCodePadding,
                Margin          = InlineCodeMargin
            };

            // Aligns content in InlineUI, see https://social.msdn.microsoft.com/Forums/silverlight/en-US/48b5e91e-efc5-4768-8eaf-f897849fcf0b/richtextbox-inlineuicontainer-vertical-alignment-issue?forum=silverlightarchieve
            border.RenderTransform = new TranslateTransform
            {
                Y = 4
            };

            var codeInline = new Inlines.CodeUIElementInline
            {
                Child = border,
                Text  = text.Text
            };

            localContext.InlineCollection.Add(codeInline);
        }
Пример #9
0
        static Common()
        {
            BoldItalicTextInline.AddTripChars(_triggerList);
            UnderlineTextInline.AddTripChars(_triggerList);
            BoldTextInline.AddTripChars(_triggerList);
            ItalicTextInline.AddTripChars(_triggerList);
            MarkdownLinkInline.AddTripChars(_triggerList);
            HyperlinkInline.AddTripChars(_triggerList);
            StrikethroughTextInline.AddTripChars(_triggerList);
            CodeInline.AddTripChars(_triggerList);
            ImageInline.AddTripChars(_triggerList);
            EmojiInline.AddTripChars(_triggerList);
            LinkAnchorInline.AddTripChars(_triggerList);
            DiscordInline.AddTripChars(_triggerList);
            SpoilerTextInline.AddTripChars(_triggerList);

            // Create an array of characters to search against using IndexOfAny.
            _tripCharacters = _triggerList.Select(trigger => trigger.FirstChar).Distinct().ToArray();
        }
Пример #10
0
        /// <summary>
        /// Renders a code element
        /// </summary>
        /// <param name="element"> The parsed inline element to render. </param>
        /// <param name="context"> Persistent state. </param>
        protected override void RenderCodeRun(CodeInline element, IRenderContext context)
        {
            var localContext = context as InlineRenderContext;

            if (localContext == null)
            {
                throw new RenderContextIncorrectException();
            }

            var text = CollapseWhitespace(context, element.Text);

            // Avoid a crash if the current inline is inside an hyperline.
            // This happens when using inline code blocks like [`SomeCode`](https://www.foo.bar).
            if (localContext.Parent is Hyperlink)
            {
                // Fallback span
                Run run = new Run
                {
                    Text       = text,
                    FontFamily = InlineCodeFontFamily ?? FontFamily,
                    Foreground = InlineCodeForeground ?? Foreground
                };

                // Additional formatting
                if (localContext.WithinItalics)
                {
                    run.FontStyle = FontStyle.Italic;
                }

                if (localContext.WithinBold)
                {
                    run.FontWeight = FontWeights.Bold;
                }

                // Add the fallback block
                localContext.InlineCollection.Add(run);
            }
            else
            {
                var textBlock = CreateTextBlock(localContext);
                textBlock.Text       = text;
                textBlock.FontFamily = InlineCodeFontFamily ?? FontFamily;
                textBlock.Foreground = InlineCodeForeground ?? Foreground;

                if (localContext.WithinItalics)
                {
                    textBlock.FontStyle = FontStyle.Italic;
                }

                if (localContext.WithinBold)
                {
                    textBlock.FontWeight = FontWeights.Bold;
                }

                var inlineUIContainer = new InlineUIContainer
                {
                    Child = new Border
                    {
                        BorderThickness = InlineCodeBorderThickness,
                        BorderBrush     = InlineCodeBorderBrush,
                        Background      = InlineCodeBackground,
                        Child           = textBlock,
                        Padding         = InlineCodePadding,
                        Margin          = InlineCodeMargin,

                        // Aligns content in InlineUI, see https://social.msdn.microsoft.com/Forums/silverlight/en-US/48b5e91e-efc5-4768-8eaf-f897849fcf0b/richtextbox-inlineuicontainer-vertical-alignment-issue?forum=silverlightarchieve
                        RenderTransform = new TranslateTransform {
                            Y = 4
                        }
                    }
                };

                // Add it to the current inlines
                localContext.InlineCollection.Add(inlineUIContainer);
            }
        }
Пример #11
0
        /// <summary>
        /// Finds the next inline element by matching trip chars and verifying the match.
        /// </summary>
        /// <param name="markdown"> The markdown text to parse. </param>
        /// <param name="start"> The position to start parsing. </param>
        /// <param name="end"> The position to stop parsing. </param>
        /// <param name="ignoreLinks"> Indicates whether to parse links. </param>
        /// <returns>Returns the next element</returns>
        private static InlineParseResult FindNextInlineElement(string markdown, int start, int end, bool ignoreLinks)
        {
            // Search for the next inline sequence.
            for (int pos = start; pos < end; pos++)
            {
                // IndexOfAny should be the fastest way to skip characters we don't care about.
                pos = markdown.IndexOfAny(_tripCharacters, pos, end - pos);
                if (pos < 0)
                {
                    break;
                }

                // Find the trigger(s) that matched.
                char currentChar = markdown[pos];
                foreach (InlineTripCharHelper currentTripChar in _triggerList)
                {
                    // Check if our current char matches the suffix char.
                    if (currentChar == currentTripChar.FirstChar)
                    {
                        // Don't match if the previous character was a backslash.
                        if (pos > start && markdown[pos - 1] == '\\')
                        {
                            continue;
                        }

                        // If we are here we have a possible match. Call into the inline class to verify.
                        InlineParseResult parseResult = null;
                        switch (currentTripChar.Method)
                        {
                        case InlineParseMethod.BoldItalic:
                            parseResult = BoldItalicTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Comment:
                            parseResult = CommentInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.LinkReference:
                            parseResult = LinkAnchorInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Bold:
                            parseResult = BoldTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Italic:
                            parseResult = ItalicTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.MarkdownLink:
                            if (!ignoreLinks)
                            {
                                parseResult = MarkdownLinkInline.Parse(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.AngleBracketLink:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseAngleBracketLink(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.Url:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseUrl(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.RedditLink:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseRedditLink(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.PartialLink:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParsePartialLink(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.Email:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseEmailAddress(markdown, start, pos, end);
                            }

                            break;

                        case InlineParseMethod.Strikethrough:
                            parseResult = StrikethroughTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Superscript:
                            parseResult = SuperscriptTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Subscript:
                            parseResult = SubscriptTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Code:
                            parseResult = CodeInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Image:
                            parseResult = ImageInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Emoji:
                            parseResult = EmojiInline.Parse(markdown, pos, end);
                            break;
                        }

                        if (parseResult != null)
                        {
                            return(parseResult);
                        }
                    }
                }
            }

            // If we didn't find any elements we have a normal text block.
            // Let us consume the entire range.
            return(new InlineParseResult(TextRunInline.Parse(markdown, start, end), start, end));
        }
Пример #12
0
 /// <summary>
 /// Renders a code element
 /// </summary>
 /// <param name="element"> The parsed inline element to render. </param>
 /// <param name="context"> Persistent state. </param>
 protected abstract void RenderCodeRun(CodeInline element, IRenderContext context);
Пример #13
0
 protected virtual void AddCodeInLine(CodeInline codeInline)
 => AddText(codeInline.Content, t => { t.Colour = Color4.Orange; });
Пример #14
0
 protected override void AddCodeInLine(CodeInline codeInline) => AddDrawable(new OsuMarkdownInlineCode
 {
     Text = codeInline.Content
 });
Пример #15
0
 // TODO : Add background (colour B6) and change font to monospace
 protected override void AddCodeInLine(CodeInline codeInline)
 => AddText(codeInline.Content, t => { t.Colour = colourProvider.Light1; });
 protected override void RenderCodeRun(CodeInline element, IRenderContext context)
 {
     //throw new NotImplementedException();
 }
Пример #17
0
        public override bool Match(InlineProcessor processor, ref StringSlice slice)
        {
            var match = slice.CurrentChar;

            if (slice.PeekCharExtra(-1) == match)
            {
                return(false);
            }

            var startPosition = slice.Start;

            // Match the opened sticks
            int openSticks   = slice.CountAndSkipChar(match);
            int contentStart = slice.Start;
            int closeSticks  = 0;

            char c = slice.CurrentChar;

            var builder = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);

            // A backtick string is a string of one or more backtick characters (`) that is neither preceded nor followed by a backtick.
            // A code span begins with a backtick string and ends with a backtick string of equal length.
            // The contents of the code span are the characters between the two backtick strings, normalized in the following ways:

            // 1. line endings are converted to spaces.

            // 2. If the resulting string both begins AND ends with a space character, but does not consist entirely
            // of space characters, a single space character is removed from the front and back.
            // This allows you to include code that begins or ends with backtick characters, which must be separated by
            // whitespace from the opening or closing backtick strings.

            bool allSpace        = true;
            bool containsNewLine = false;
            var  contentEnd      = -1;

            while (c != '\0')
            {
                // Transform '\n' into a single space
                if (c == '\n')
                {
                    containsNewLine = true;
                    c = ' ';
                }
                else if (c == '\r')
                {
                    containsNewLine = true;
                    slice.SkipChar();
                    c = slice.CurrentChar;
                    continue;
                }

                if (c == match)
                {
                    contentEnd  = slice.Start;
                    closeSticks = slice.CountAndSkipChar(match);

                    if (openSticks == closeSticks)
                    {
                        break;
                    }

                    allSpace = false;
                    builder.Append(match, closeSticks);
                    c = slice.CurrentChar;
                }
                else
                {
                    builder.Append(c);
                    if (c != ' ')
                    {
                        allSpace = false;
                    }
                    c = slice.NextChar();
                }
            }

            bool isMatching = false;

            if (closeSticks == openSticks)
            {
                ReadOnlySpan <char> contentSpan = builder.AsSpan();

                var content = containsNewLine
                    ? new LazySubstring(contentSpan.ToString())
                    : new LazySubstring(slice.Text, contentStart, contentSpan.Length);

                Debug.Assert(contentSpan.SequenceEqual(content.AsSpan()));

                // Remove one space from front and back if the string is not all spaces
                if (!allSpace && contentSpan.Length > 2 && contentSpan[0] == ' ' && contentSpan[contentSpan.Length - 1] == ' ')
                {
                    content.Offset++;
                    content.Length -= 2;
                }

                int delimiterCount = Math.Min(openSticks, closeSticks);
                var spanStart      = processor.GetSourcePosition(startPosition, out int line, out int column);
                var spanEnd        = processor.GetSourcePosition(slice.Start - 1);
                var codeInline     = new CodeInline(content)
                {
                    Delimiter      = match,
                    Span           = new SourceSpan(spanStart, spanEnd),
                    Line           = line,
                    Column         = column,
                    DelimiterCount = delimiterCount,
                };

                if (processor.TrackTrivia)
                {
                    codeInline.ContentWithTrivia = new StringSlice(slice.Text, contentStart, contentEnd - 1);
                }

                processor.Inline = codeInline;
                isMatching       = true;
            }

            builder.Dispose();
            return(isMatching);
        }
Пример #18
0
 protected override void RenderCodeRun(CodeInline element, IRenderContext context)
 {
 }
Пример #19
0
 public Code(CodeInline code) : base(code) =>
     this.Content = code.Content;