Beispiel #1
0
        static Common()
        {
            BoldItalicTextInline.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();
        }
Beispiel #2
0
        private void RenderDiscord(InlineCollection inlineCollection, DiscordInline element, RenderContext context)
        {
            if (!element.IsEmote)
            {
                var link = new Hyperlink();

                // Register the link
                _linkRegister.RegisterNewHyperLink(link, element.Url);

                // Make a text block for the link
                Run linkText = new Run
                {
                    Text = CollapseWhitespace(context, element.Text)
                };
                link.Inlines.Add(linkText);

                // Add it to the current inlines
                inlineCollection.Add(link);
            }
            else
            {
                // in this case we just huck the emote inline instead

                inlineCollection.Add(new InlineUIContainer {
                    Child = new Image {
                        HorizontalAlignment = HorizontalAlignment.Center,
                        MaxHeight           = 30,
                        MaxWidth            = 30,
                        Source = new BitmapImage {
                            DecodePixelType   = DecodePixelType.Logical,
                            DecodePixelHeight = 30,
                            UriSource         = new Uri(element.Url),
                        },
                    }
                });
            }
        }
Beispiel #3
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.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.Spoiler:
                            parseResult = SpoilerTextInline.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;

                        case InlineParseMethod.Discord:
                            parseResult = DiscordInline.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));
        }
Beispiel #4
0
        protected override void RenderDiscord(DiscordInline element, IRenderContext context)
        {
            if (!(context is InlineRenderContext localContext))
            {
                throw new RenderContextIncorrectException();
            }

            if (Channel != null)
            {
                var guild  = Channel.Guild;
                var client = Channel.Discord as DiscordClient;

                if (element.DiscordType != DiscordInline.MentionType.Emote)
                {
                    var run = new Run()
                    {
                        FontWeight = FontWeights.Bold
                    };

                    if (element.DiscordType == DiscordInline.MentionType.User)
                    {
                        var user = guild != null ? (guild.Members.TryGetValue(element.Id, out var memb) ? memb : null) : client.TryGetCachedUser(element.Id, out var u) ? u : null;
                        if (user != null)
                        {
                            run.Text       = IsSystemMessage ? user.DisplayName : $"@{user.DisplayName}";
                            run.Foreground = GetDiscordBrush(user.Color);
                        }
                        else
                        {
                            run.Text = $"<@{element.Id}>";
                        }
                    }
                    else if (element.DiscordType == DiscordInline.MentionType.Role)
                    {
                        if (Channel.Guild != null && Channel.Guild.Roles.TryGetValue(element.Id, out var role))
                        {
                            run.Text       = $"@{role.Name}";
                            run.Foreground = GetDiscordBrush(role.Color);
                        }
                        else
                        {
                            run.Text = $"<@&{element.Id}>";
                        }
                    }
                    else if (element.DiscordType == DiscordInline.MentionType.Channel)
                    {
                        if (client.TryGetCachedChannel(element.Id, out var channel) && !(channel is DiscordDmChannel))
                        {
                            run.Text = $"#{channel.Name}";
                        }
                        else
                        {
                            run.Text = $"#deleted-channel";
                        }
                    }


                    localContext.InlineCollection.Add(run);
                }
                else
                {
                    var border = RootElement.FindParent <Border>();
                    var uri    = $"https://cdn.discordapp.com/emojis/{element.Id}?size=128";
                    var ui     = new InlineUIContainer()
                    {
                        FontSize = IsHuge ? 42 : 24
                    };
                    var size  = IsHuge ? 48 : 24;
                    var image = new EmojiControl()
                    {
                        Emoji           = DiscordEmoji.FromGuildEmote(App.Discord, element.Id, element.Text),
                        Size            = size,
                        MaxWidth        = size * 3,
                        RenderTransform = IsHuge ? null : new TranslateTransform()
                        {
                            Y = 8
                        }
                    };

                    ToolTipService.SetToolTip(image, element.Text);
                    ui.Child = image;

                    RootElement.Margin = new Thickness(0, 0, 0, 4);
                    localContext.InlineCollection.Add(ui);

                    if (!IsHuge && RootElement.RenderTransform is not TranslateTransform tt)
                    {
                        RootElement.Margin = new Thickness(0, -8, 0, 0);
                    }
                }
            }
        }
        protected override void RenderDiscord(DiscordInline element, IRenderContext context)
        {
            if (!(context is InlineRenderContext localContext))
            {
                throw new RenderContextIncorrectException();
            }

            if (Channel != null)
            {
                var guild  = Channel.Guild;
                var client = Channel.Discord as DiscordClient;

                if (element.DiscordType != DiscordInline.MentionType.Emote)
                {
                    var run = new Run()
                    {
                        FontWeight = FontWeights.Bold
                    };

                    if (element.DiscordType == DiscordInline.MentionType.User)
                    {
                        var user = guild != null ? (guild.Members.TryGetValue(element.Id, out var memb) ? memb : null) : client.UserCache.TryGetValue(element.Id, out var u) ? u : null;
                        if (user != null)
                        {
                            var me = user as DiscordMember;

                            run.Text       = $"@{me?.DisplayName ?? user.Username}";
                            run.Foreground = me?.ColorBrush ?? Foreground;
                        }
                        else
                        {
                            run.Text = $"<@{element.Id}>";
                        }
                    }
                    else if (element.DiscordType == DiscordInline.MentionType.Role)
                    {
                        var role = client.Guilds.Values.SelectMany(g => g.Roles.Values).FirstOrDefault(r => r.Id == element.Id);
                        if (role != null)
                        {
                            run.Text = $"@{role.Name}";
                            if (role.Color.Value != 0)
                            {
                                run.Foreground = new SolidColorBrush(Color.FromArgb(255, role.Color.R, role.Color.G, role.Color.B));
                            }
                        }
                        else
                        {
                            run.Text = $"<@&{element.Id}>";
                        }
                    }
                    else if (element.DiscordType == DiscordInline.MentionType.Channel)
                    {
                        if (client._channelCache.TryGetValue(element.Id, out var channel))
                        {
                            run.Text = channel is DiscordDmChannel c ? $"@{c.Recipient.Username}#{c.Recipient.Id}" : $"#{channel.Name}";
                        }
                        else
                        {
                            run.Text = $"#deleted-channel";
                        }
                    }


                    localContext.InlineCollection.Add(run);
                }
                else
                {
                    var uri = $"https://cdn.discordapp.com/emojis/{element.Id}?size=32";
                    var ui  = new InlineUIContainer()
                    {
                        FontSize = 24
                    };

                    var image = new Image()
                    {
                        Source          = new BitmapImage(new Uri(uri)),
                        Width           = 24,
                        Height          = 24,
                        Stretch         = Stretch.Uniform,
                        RenderTransform = new TranslateTransform()
                        {
                            Y = 4
                        }
                    };

                    ToolTipService.SetToolTip(image, element.Text);
                    ui.Child = image;

                    RootElement.Margin = new Thickness(0, 0, 0, 4);
                    localContext.InlineCollection.Add(ui);
                }
            }
        }
Beispiel #6
0
 /// <summary>
 /// Renders a Discord element.
 /// </summary>
 /// <param name="element"> The parsed inline element to render. </param>
 /// <param name="context"> Persistent state. </param>
 protected abstract void RenderDiscord(DiscordInline element, IRenderContext context);