Represents a span containing plain text.
Inheritance: MarkdownInline, IInlineLeaf
コード例 #1
0
        /// <summary>
        /// This function can be called by any element parsing. Given a start and stopping point this will
        /// parse all found elements out of the range.
        /// </summary>
        /// <param name="markdown"></param>
        /// <param name="startingPos"></param>
        /// <param name="maxEndingPos"></param>
        protected void ParseInlineChildren(ref string markdown, int startingPos, int maxEndingPos)
        {
            int currentParsePosition = startingPos;


            while (currentParsePosition < maxEndingPos)
            {
                int nextElemntStart = 0;
                int nextElementEnd = 0;

                // Find the next element
                MarkdownInline element = Common.FindNextInlineElement(ref markdown, currentParsePosition, maxEndingPos, ref nextElemntStart, ref nextElementEnd);

                // If the element we found doesn't start at the position we are looking for there is text between the element and
                // the start. We need to wrap it into a Text Run
                if (nextElemntStart != currentParsePosition)
                {
                    TextRunInline textRun = new TextRunInline();
                    textRun.Parse(ref markdown, currentParsePosition, nextElemntStart);
                    Children.Add(textRun);
                }

                // Ask it to parse, it will return us the ending pos of itself.
                currentParsePosition = element.Parse(ref markdown, nextElemntStart, nextElementEnd);

                // Add it the the children
                Children.Add(element);
            }
        }
コード例 #2
0
        /// <summary>
        /// Called when the object should parse it's goods out of the markdown. The markdown, start, and stop are given.
        /// The start and stop are what is returned from the FindNext function below. The object should do it's parsing and
        /// return up to the last pos it used. This can be shorter than what is given to the function in endingPos.
        /// </summary>
        /// <param name="markdown">The markdown</param>
        /// <param name="startingPos">Where the parse should start</param>
        /// <param name="endingPos">Where the parse should end</param>
        /// <returns></returns>
        internal override int Parse(ref string markdown, int startingPos, int endingPos)
        {
            // Find all of the link parts
            int linkTextOpen = Common.IndexOf(ref markdown, '[', startingPos, endingPos);
            int linkTextClose = Common.IndexOf(ref markdown, ']', linkTextOpen, endingPos);
            int linkOpen = Common.IndexOf(ref markdown, '(', linkTextClose, endingPos);
            int linkClose = Common.IndexOf(ref markdown, ')', linkOpen, endingPos);

            // These should always be =
            if (linkTextOpen != startingPos)
            {
                DebuggingReporter.ReportCriticalError("link parse didn't find [ in at the starting pos");
            }
            if (linkClose + 1 != endingPos)
            {
                DebuggingReporter.ReportCriticalError("link parse didn't find ] in at the end pos");
            }

            // Make sure there is something to parse, and not just dead space
            linkTextOpen++;
            if (linkTextClose > linkTextOpen)
            {
                // Parse any children of this link element
                ParseInlineChildren(ref markdown, linkTextOpen, linkTextClose);
            }

            // We can't render links in links. So if anything in the children of this is a link
            // we have to remove it
            for(int count = 0; count < Children.Count; count++)
            {
                // Look through the children for a link, if found grab the text
                MarkdownInlineType type = ((MarkdownInline)Children[count]).Type;
                string replaceText = null;
                if (type == MarkdownInlineType.MarkdownLink)
                {
                    // If it is a link just grab the URL. Ideally we would grab the text
                    // but that is too hard and this will never happen.
                    replaceText = ((MarkdownLinkInline)Children[count]).Url;
                }
                else if (type == MarkdownInlineType.RawHyperlink)
                {
                    replaceText = ((RawHyperlinkInline)Children[count]).Url;
                }
                else if (type == MarkdownInlineType.RawSubreddit)
                {
                    replaceText = ((RawSubredditInline)Children[count]).Text;
                }

                // If we found text to replace add a new text element as the text.
                if(replaceText != null)
                {
                    TextRunInline textRun = new TextRunInline();
                    textRun.Text = replaceText;
                    Children[count] = textRun;
                }
            }

            // Grab the link
            linkOpen++;
            Url = markdown.Substring(linkOpen, linkClose - linkOpen);

            // Return the point after the )
            return linkClose + 1;
        }
コード例 #3
0
        /// <summary>
        /// Attempts to parse a reference e.g. "[example]: http://www.reddit.com 'title'".
        /// </summary>
        /// <param name="markdown"> The markdown text. </param>
        /// <param name="start"> The location to start parsing. </param>
        /// <param name="end"> The location to stop parsing. </param>
        /// <returns> A parsed markdown link, or <c>null</c> if this is not a markdown link. </returns>
        internal static LinkReferenceBlock Parse(string markdown, int start, int end)
        {
            // Expect a '[' character.
            if (start >= end || markdown[start] != '[')
            {
                return(null);
            }

            // Find the ']' character
            int pos = start + 1;

            while (pos < end)
            {
                if (markdown[pos] == ']')
                {
                    break;
                }
                pos++;
            }
            if (pos == end)
            {
                return(null);
            }

            // Extract the ID.
            string id = markdown.Substring(start + 1, pos - (start + 1));

            // Expect the ':' character.
            pos++;
            if (pos == end || markdown[pos] != ':')
            {
                return(null);
            }

            // Skip whitespace
            pos++;
            while (pos < end && Common.IsWhiteSpace(markdown[pos]))
            {
                pos++;
            }
            if (pos == end)
            {
                return(null);
            }

            // Extract the URL.
            int urlStart = pos;

            while (pos < end && !Common.IsWhiteSpace(markdown[pos]))
            {
                pos++;
            }
            string url = TextRunInline.ResolveEscapeSequences(markdown, urlStart, pos);

            // Ignore leading '<' and trailing '>'.
            url = url.TrimStart('<').TrimEnd('>');

            // Skip whitespace.
            pos++;
            while (pos < end && Common.IsWhiteSpace(markdown[pos]))
            {
                pos++;
            }

            string tooltip = null;

            if (pos < end)
            {
                // Extract the tooltip.
                char tooltipEndChar;
                switch (markdown[pos])
                {
                case '(':
                    tooltipEndChar = ')';
                    break;

                case '"':
                case '\'':
                    tooltipEndChar = markdown[pos];
                    break;

                default:
                    return(null);
                }
                pos++;
                int tooltipStart = pos;
                while (pos < end && markdown[pos] != tooltipEndChar)
                {
                    pos++;
                }
                if (pos == end)
                {
                    return(null);    // No end character.
                }
                tooltip = markdown.Substring(tooltipStart, pos - tooltipStart);

                // Check there isn't any trailing text.
                pos++;
                while (pos < end && Common.IsWhiteSpace(markdown[pos]))
                {
                    pos++;
                }
                if (pos < end)
                {
                    return(null);
                }
            }

            // We found something!
            var result = new LinkReferenceBlock();

            result.Id      = id;
            result.Url     = url;
            result.Tooltip = tooltip;
            return(result);
        }
コード例 #4
0
        /// <summary>
        /// Attempts to parse a markdown link e.g. "[](http://www.reddit.com)".
        /// </summary>
        /// <param name="markdown"> The markdown text. </param>
        /// <param name="start"> The location to start parsing. </param>
        /// <param name="maxEnd"> The location to stop parsing. </param>
        /// <returns> A parsed markdown link, or <c>null</c> if this is not a markdown link. </returns>
        internal static Common.InlineParseResult Parse(string markdown, int start, int maxEnd)
        {
            // Expect a '[' character.
            if (start == maxEnd || markdown[start] != '[')
            {
                return(null);
            }

            // Find the ']' character, keeping in mind that [test [0-9]](http://www.test.com) is allowed.
            int linkTextOpen = start + 1;
            int pos          = linkTextOpen;
            int linkTextClose;
            int openSquareBracketCount = 0;

            while (true)
            {
                linkTextClose = markdown.IndexOfAny(new char[] { '[', ']' }, pos, maxEnd - pos);
                if (linkTextClose == -1)
                {
                    return(null);
                }
                if (markdown[linkTextClose] == '[')
                {
                    openSquareBracketCount++;
                }
                else if (openSquareBracketCount > 0)
                {
                    openSquareBracketCount--;
                }
                else
                {
                    break;
                }
                pos = linkTextClose + 1;
            }

            // Skip whitespace.
            pos = linkTextClose + 1;
            while (pos < maxEnd && Common.IsWhiteSpace(markdown[pos]))
            {
                pos++;
            }
            if (pos == maxEnd)
            {
                return(null);
            }

            // Expect the '(' character or the '[' character.
            int linkOpen = pos;

            if (markdown[pos] == '(')
            {
                // Skip whitespace.
                linkOpen++;
                while (linkOpen < maxEnd && Common.IsWhiteSpace(markdown[linkOpen]))
                {
                    linkOpen++;
                }

                // Find the ')' character.
                pos = linkOpen;
                int linkClose = -1;
                while (pos < maxEnd)
                {
                    linkClose = Common.IndexOf(markdown, ')', pos, maxEnd);
                    if (linkClose == -1)
                    {
                        return(null);
                    }
                    if (markdown[linkClose - 1] != '\\')
                    {
                        break;
                    }
                    pos = linkClose + 1;
                }
                if (pos >= maxEnd)
                {
                    return(null);
                }
                int end = linkClose + 1;

                // Skip whitespace backwards.
                while (linkClose > linkOpen && Common.IsWhiteSpace(markdown[linkClose - 1]))
                {
                    linkClose--;
                }

                // If there is no text whatsoever, then this is not a valid link.
                if (linkOpen == linkClose)
                {
                    return(null);
                }

                // Check if there is tooltip text.
                string url;
                string tooltip = null;
                bool   lastUrlCharIsDoubleQuote = markdown[linkClose - 1] == '"';
                int    tooltipStart             = Common.IndexOf(markdown, " \"", linkOpen, linkClose - 1);
                if (tooltipStart == linkOpen)
                {
                    return(null);
                }
                if (lastUrlCharIsDoubleQuote && tooltipStart != -1)
                {
                    // Extract the URL (resolving any escape sequences).
                    url     = TextRunInline.ResolveEscapeSequences(markdown, linkOpen, tooltipStart).TrimEnd(' ', '\t', '\r', '\n');
                    tooltip = markdown.Substring(tooltipStart + 2, (linkClose - 1) - (tooltipStart + 2));
                }
                else
                {
                    // Extract the URL (resolving any escape sequences).
                    url = TextRunInline.ResolveEscapeSequences(markdown, linkOpen, linkClose);
                }

                // Check the URL is okay.
                if (!IsUrlValid(url))
                {
                    return(null);
                }

                // We found a regular stand-alone link.
                var result = new MarkdownLinkInline();
                result.Inlines = Common.ParseInlineChildren(markdown, linkTextOpen, linkTextClose, ignoreLinks: true);
                result.Url     = url.Replace(" ", "%20");
                result.Tooltip = tooltip;
                return(new Common.InlineParseResult(result, start, end));
            }
            else if (markdown[pos] == '[')
            {
                // Find the ']' character.
                int linkClose = Common.IndexOf(markdown, ']', pos + 1, maxEnd);
                if (linkClose == -1)
                {
                    return(null);
                }

                // We found a reference-style link.
                var result = new MarkdownLinkInline();
                result.Inlines     = Common.ParseInlineChildren(markdown, linkTextOpen, linkTextClose, ignoreLinks: true);
                result.ReferenceId = markdown.Substring(linkOpen + 1, linkClose - (linkOpen + 1));
                if (result.ReferenceId == string.Empty)
                {
                    result.ReferenceId = markdown.Substring(linkTextOpen, linkTextClose - linkTextOpen);
                }
                return(new Common.InlineParseResult(result, start, linkClose + 1));
            }
            return(null);
        }
コード例 #5
0
        /// <summary>
        /// Called when the object should parse it's goods out of the markdown. The markdown, start, and stop are given.
        /// The start and stop are what is returned from the FindNext function below. The object should do it's parsing and
        /// return up to the last pos it used. This can be shorter than what is given to the function in endingPos.
        /// </summary>
        /// <param name="markdown">The markdown</param>
        /// <param name="startingPos">Where the parse should start</param>
        /// <param name="endingPos">Where the parse should end</param>
        /// <returns></returns>
        internal override int Parse(ref string markdown, int startingPos, int endingPos)
        {
            // Find all of the link parts
            int linkTextOpen  = Common.IndexOf(ref markdown, '[', startingPos, endingPos);
            int linkTextClose = Common.IndexOf(ref markdown, ']', linkTextOpen, endingPos);
            int linkOpen      = Common.IndexOf(ref markdown, '(', linkTextClose, endingPos);
            int linkClose     = Common.IndexOf(ref markdown, ')', linkOpen, endingPos);

            // These should always be =
            if (linkTextOpen != startingPos)
            {
                DebuggingReporter.ReportCriticalError("link parse didn't find [ in at the starting pos");
            }
            if (linkClose + 1 != endingPos)
            {
                DebuggingReporter.ReportCriticalError("link parse didn't find ] in at the end pos");
            }

            // Make sure there is something to parse, and not just dead space
            linkTextOpen++;
            if (linkTextClose > linkTextOpen)
            {
                // Parse any children of this link element
                ParseInlineChildren(ref markdown, linkTextOpen, linkTextClose);
            }

            // We can't render links in links. So if anything in the children of this is a link
            // we have to remove it
            for (int count = 0; count < Children.Count; count++)
            {
                // Look through the children for a link, if found grab the text
                MarkdownInlineType type        = ((MarkdownInline)Children[count]).Type;
                string             replaceText = null;
                if (type == MarkdownInlineType.MarkdownLink)
                {
                    // If it is a link just grab the URL. Ideally we would grab the text
                    // but that is too hard and this will never happen.
                    replaceText = ((MarkdownLinkInline)Children[count]).Url;
                }
                else if (type == MarkdownInlineType.RawHyperlink)
                {
                    replaceText = ((RawHyperlinkInline)Children[count]).Url;
                }
                else if (type == MarkdownInlineType.RawSubreddit)
                {
                    replaceText = ((RawSubredditInline)Children[count]).Text;
                }

                // If we found text to replace add a new text element as the text.
                if (replaceText != null)
                {
                    TextRunInline textRun = new TextRunInline();
                    textRun.Text    = replaceText;
                    Children[count] = textRun;
                }
            }

            // Grab the link
            linkOpen++;
            Url = markdown.Substring(linkOpen, linkClose - linkOpen);

            // Return the point after the )
            return(linkClose + 1);
        }
コード例 #6
0
        /// <summary>
        /// Renders a text run 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 RenderTextRun(InlineCollection inlineCollection, TextRunInline element, TextElement parent, RenderContext context)
        {
            // Create the text run
            Run textRun = new Run();
            textRun.Text = CollapseWhitespace(context, element.Text);

            // Add it
            inlineCollection.Add(textRun);
        }
コード例 #7
0
        /// <summary>
        /// Renders a text run element.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="currentInlines"></param>
        /// <param name="trimTextStart">If true this element should trin the start of the text and set to fales.</param>
        private void RenderTextRun(TextRunInline element, InlineCollection currentInlines, ref bool trimTextStart)
        {
            // Create the text run
            Run textRun = new Run();
            textRun.Text = element.Text;

            // Check if we should trim the starting text. This allows us to trim the text starting a block
            // but nothing else. If we do a trim set it to false so no one else does.
            if(trimTextStart)
            {
                trimTextStart = false;
                textRun.Text = textRun.Text.TrimStart();
            }

            // Add it
            currentInlines.Add(textRun);
        }