Exemplo n.º 1
0
        internal static void MatchSquareBracketStack(InlineStack opener, Subject subj, Reference details)
        {
            if (details != null)
            {
                var inl     = opener.StartingInline;
                var isImage = 0 != (opener.Flags & InlineStack.InlineStackFlags.ImageLink);
                inl.Tag                = isImage ? InlineTag.Image : (details.IsPlaceholder ? InlineTag.Placeholder : InlineTag.Link);
                inl.FirstChild         = inl.NextSibling;
                inl.NextSibling        = null;
                inl.SourceLastPosition = subj.Position;

                inl.TargetUrl      = details.Url;
                inl.LiteralContent = details.Title;

                if (!isImage && !details.IsPlaceholder)
                {
                    // since there cannot be nested links, remove any other link openers before this
                    var temp = opener.Previous;
                    while (temp != null && temp.Priority <= InlineStack.InlineStackPriority.Links)
                    {
                        if (temp.Delimiter == '[' && temp.Flags == opener.Flags)
                        {
                            // mark the previous entries as "inactive"
                            if (temp.DelimiterCount == -1)
                            {
                                break;
                            }

                            temp.DelimiterCount = -1;
                        }

                        temp = temp.Previous;
                    }
                }

                InlineStack.RemoveStackEntry(opener, subj, null);

                subj.LastInline = inl;
            }
            else
            {
                // this looked like a link, but was not.
                // remove the opener stack entry but leave the inbetween intact
                InlineStack.RemoveStackEntry(opener, subj, opener);

                var inl = new Inline("]", subj.Position - 1, subj.Position);
                subj.LastInline.LastSibling.NextSibling = inl;
                subj.LastInline = inl;
            }
        }
Exemplo n.º 2
0
        private static Inline HandleRightSquareBracket(Subject subj, bool supportPlaceholderBrackets)
        {
            // move past ']'
            subj.Position++;

            bool canClose;
            var  istack = InlineStack.FindMatchingOpener(subj.LastPendingInline, InlineStack.InlineStackPriority.Links, '[', 1, false, out canClose);

            if (istack != null)
            {
                // if the opener is "inactive" then it means that there was a nested link
                if (istack.DelimiterCount == -1)
                {
                    InlineStack.RemoveStackEntry(istack, subj, istack);
                    return(new Inline("]", subj.Position - 1, subj.Position));
                }

                var endpos = subj.Position;

                // try parsing details for '[foo](/url "title")' or '[foo][bar]'
                //var details = ParseLinkDetails(subj);
                var details = ParseLinkDetails(subj, supportPlaceholderBrackets);

                // try lookup of the brackets themselves
                if (details == null || details == Reference.SelfReference)
                {
                    var startpos = istack.StartPosition;
                    var label    = new StringPart(subj.Buffer, startpos, endpos - startpos - 1);

                    details = LookupReference(subj.DocumentData, label);
                }

                if (details == Reference.InvalidReference)
                {
                    details = null;
                }

                MatchSquareBracketStack(istack, subj, details);
                return(null);
            }

            var inlText = new Inline("]", subj.Position - 1, subj.Position);

            if (canClose)
            {
                // note that the current implementation will not work if there are other inlines with priority
                // higher than Links.
                // to fix this the parsed link details should be added to the closer element in the stack.

                throw new NotSupportedException("It is not supported to have inline stack priority higher than Links.");

                ////istack = new InlineStack();
                ////istack.Delimiter = '[';
                ////istack.StartingInline = inlText;
                ////istack.StartPosition = subj.Position;
                ////istack.Priority = InlineStack.InlineStackPriority.Links;
                ////istack.Flags = InlineStack.InlineStackFlags.Closer;

                ////InlineStack.AppendStackEntry(istack, subj);
            }

            return(inlText);
        }
Exemplo n.º 3
0
        internal static int MatchInlineStack(InlineStack opener, Subject subj, int closingDelimiterCount, InlineStack closer, InlineTag singleCharTag, InlineTag doubleCharTag)
        {
            // calculate the actual number of delimiters used from this closer
            int useDelims;
            var openerDelims = opener.DelimiterCount;

            if (closingDelimiterCount < 3 || openerDelims < 3)
            {
                useDelims = closingDelimiterCount <= openerDelims ? closingDelimiterCount : openerDelims;
                if (useDelims == 1 && singleCharTag == 0)
                {
                    return(0);
                }
            }
            else if (singleCharTag == 0)
            {
                useDelims = 2;
            }
            else if (doubleCharTag == 0)
            {
                useDelims = 1;
            }
            else
            {
                useDelims = closingDelimiterCount % 2 == 0 ? 2 : 1;
            }

            Inline    inl = opener.StartingInline;
            InlineTag tag = useDelims == 1 ? singleCharTag : doubleCharTag;

            if (openerDelims == useDelims)
            {
                // the opener is completely used up - remove the stack entry and reuse the inline element
                inl.Tag            = tag;
                inl.LiteralContent = null;
                inl.FirstChild     = inl.NextSibling;
                inl.NextSibling    = null;

                InlineStack.RemoveStackEntry(opener, subj, closer?.Previous);
            }
            else
            {
                // the opener will only partially be used - stack entry remains (truncated) and a new inline is added.
                opener.DelimiterCount  -= useDelims;
                inl.LiteralContent      = inl.LiteralContent.Substring(0, opener.DelimiterCount);
                inl.SourceLastPosition -= useDelims;

                inl.NextSibling = new Inline(tag, inl.NextSibling);
                inl             = inl.NextSibling;

                inl.SourcePosition = opener.StartingInline.SourcePosition + opener.DelimiterCount;
            }

            // there are two callers for this method, distinguished by the `closer` argument.
            // if closer == null it means the method is called during the initial subject parsing and the closer
            //   characters are at the current position in the subject. The main benefit is that there is nothing
            //   parsed that is located after the matched inline element.
            // if closer != null it means the method is called when the second pass for previously unmatched
            //   stack elements is done. The drawback is that there can be other elements after the closer.
            if (closer != null)
            {
                var clInl = closer.StartingInline;
                if ((closer.DelimiterCount -= useDelims) > 0)
                {
                    // a new inline element must be created because the old one has to be the one that
                    // finalizes the children of the emphasis
                    var newCloserInline = new Inline(clInl.LiteralContent.Substring(useDelims));
                    newCloserInline.SourcePosition = inl.SourceLastPosition = clInl.SourcePosition + useDelims;
                    newCloserInline.SourceLength   = closer.DelimiterCount;
                    newCloserInline.NextSibling    = clInl.NextSibling;

                    clInl.LiteralContent = null;
                    clInl.NextSibling    = null;
                    inl.NextSibling      = closer.StartingInline = newCloserInline;
                }
                else
                {
                    inl.SourceLastPosition = clInl.SourceLastPosition;

                    clInl.LiteralContent = null;
                    inl.NextSibling      = clInl.NextSibling;
                    clInl.NextSibling    = null;
                }
            }
            else if (subj != null)
            {
                inl.SourceLastPosition = subj.Position - closingDelimiterCount + useDelims;
                subj.LastInline        = inl;
            }

            return(useDelims);
        }