Esempio 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 : InlineTag.Link;
                inl.FirstChild         = inl.NextSibling;
                inl.NextSibling        = null;
                inl.SourceLastPosition = subj.Position;

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

                if (!isImage)
                {
                    // 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.Delimeter == '[' && temp.Flags == opener.Flags)
                        {
                            // mark the previous entries as "inactive"
                            if (temp.DelimeterCount == -1)
                            {
                                break;
                            }

                            temp.DelimeterCount = -1;
                        }

                        temp = temp.Previous;
                    }
                }

                InlineStack.RemoveStackEntry(opener, subj, null);

                if (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;
            }
        }
Esempio n. 2
0
        private static Inline HandleRightSquareBracket(Subject subj)
        {
            // move past ']'
            subj.Position++;

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

            if (istack != null)
            {
                // if the opener is "inactive" then it means that there was a nested link
                if (istack.DelimeterCount == -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);

                // 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.ReferenceMap, 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.Delimeter = '[';
                ////istack.StartingInline = inlText;
                ////istack.StartPosition = subj.Position;
                ////istack.Priority = InlineStack.InlineStackPriority.Links;
                ////istack.Flags = InlineStack.InlineStackFlags.Closer;

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

            return(inlText);
        }
Esempio n. 3
0
        internal static int MatchInlineStack(InlineStack opener, Subject subj, int closingDelimeterCount, InlineStack closer, InlineTag?singleCharTag, InlineTag?doubleCharTag)
        {
            // calculate the actual number of delimeters used from this closer
            int useDelims;
            var openerDelims = opener.DelimeterCount;

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

            Inline inl = opener.StartingInline;

            if (openerDelims == useDelims)
            {
                // the opener is completely used up - remove the stack entry and reuse the inline element
                inl.Tag            = useDelims == 1 ? singleCharTag.Value : doubleCharTag.Value;
                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.DelimeterCount  -= useDelims;
                inl.LiteralContent      = inl.LiteralContent.Substring(0, opener.DelimeterCount);
                inl.SourceLastPosition -= useDelims;

                inl.NextSibling = new Inline(useDelims == 1 ? singleCharTag.Value : doubleCharTag.Value, inl.NextSibling);
                inl             = inl.NextSibling;

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

            // 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.DelimeterCount -= 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.DelimeterCount;
                    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 - closingDelimeterCount + useDelims;
                subj.LastInline        = inl;
            }

            return(useDelims);
        }
Esempio n. 4
0
        public static void PostProcessInlineStack(Subject subj, InlineStack first, InlineStack last, InlineStackPriority ignorePriority)
        {
            while (ignorePriority > 0)
            {
                var istack = first;
                while (istack != null)
                {
                    if (istack.Priority >= ignorePriority)
                    {
                        InlineStack.RemoveStackEntry(istack, subj, istack);
                    }
                    else if (0 != (istack.Flags & InlineStackFlags.Closer))
                    {
                        bool canClose;
                        var  iopener = InlineStack.FindMatchingOpener(istack.Previous, istack.Priority, istack.Delimeter, out canClose);
                        if (iopener != null)
                        {
                            bool retry = false;
                            if (iopener.Delimeter == '~')
                            {
                                InlineMethods.MatchInlineStack(iopener, subj, istack.DelimeterCount, istack, null, InlineTag.Strikethrough);
                                if (istack.DelimeterCount > 1)
                                {
                                    retry = true;
                                }
                            }
                            else
                            {
                                var useDelims = InlineMethods.MatchInlineStack(iopener, subj, istack.DelimeterCount, istack, InlineTag.Emphasis, InlineTag.Strong);
                                if (istack.DelimeterCount > 0)
                                {
                                    retry = true;
                                }
                            }

                            if (retry)
                            {
                                // remove everything between opened and closer (not inclusive).
                                if (iopener.Next != istack.Previous)
                                {
                                    InlineStack.RemoveStackEntry(iopener.Next, subj, istack.Previous);
                                }

                                continue;
                            }
                            else
                            {
                                // remove opener, everything in between, and the closer
                                InlineStack.RemoveStackEntry(iopener, subj, istack);
                            }
                        }
                        else if (!canClose)
                        {
                            // this case means that a matching opener does not exist
                            // remove the Closer flag so that a future Opener can be matched against it.
                            istack.Flags &= ~InlineStackFlags.Closer;
                        }
                    }

                    if (istack == last)
                    {
                        break;
                    }

                    istack = istack.Next;
                }

                ignorePriority--;
            }
        }