Exemplo n.º 1
0
        public static void AppendStackEntry(InlineStack entry, Subject subj)
        {
            if (subj.LastPendingInline != null)
            {
                entry.Previous = subj.LastPendingInline;
                subj.LastPendingInline.Next = entry;
            }

            if (subj.FirstPendingInline is null)
            {
                subj.FirstPendingInline = entry;
            }

            subj.LastPendingInline = entry;
        }
Exemplo n.º 2
0
        public static InlineStack FindMatchingOpener(InlineStack searchBackwardsFrom, InlineStackPriority priority,
                                                     char delimiter, int closerDelimiterCount, bool closerCanOpen, out bool canClose)
        {
            canClose = true;
            var istack = searchBackwardsFrom;

            while (true)
            {
                if (istack is null)
                {
                    // this cannot be a closer since there is no opener available.
                    canClose = false;
                    return(null);
                }

                if (istack.Priority > priority ||
                    (istack.Delimiter == delimiter && 0 != (istack.Flags & InlineStackFlags.Closer)))
                {
                    // there might be a closer further back but we cannot go there yet because a higher priority element is blocking
                    // the other option is that the stack entry could be a closer for the same char - this means
                    // that any opener we might find would first have to be matched against this closer.
                    return(null);
                }

                if (istack.Delimiter == delimiter)
                {
                    // interior closer of size 2 does not match opener of size 1 and vice versa.
                    // for more details, see https://github.com/jgm/cmark/commit/c50197bab81d7105c9c790548821b61bcb97a62a
                    var oddMatch = (closerCanOpen || (istack.Flags & InlineStackFlags.CloserOriginally) > 0) &&
                                   istack.DelimiterCount != closerDelimiterCount &&
                                   ((istack.DelimiterCount + closerDelimiterCount) % 3 == 0);

                    if (!oddMatch)
                    {
                        return(istack);
                    }
                }

                istack = istack.Previous;
            }
        }
Exemplo n.º 3
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)
                    {
                        RemoveStackEntry(istack, subj, istack);
                    }
                    else if (0 != (istack.Flags & InlineStackFlags.Closer))
                    {
                        var iopener = FindMatchingOpener(istack.Previous, istack.Priority, istack.Delimiter, istack.DelimiterCount, (istack.Flags & InlineStackFlags.Opener) > 0, out bool canClose);
                        if (iopener != null)
                        {
                            bool retry = false;
                            if (iopener.Delimiter == '~')
                            {
                                InlineMethods.MatchInlineStack(iopener, subj, istack.DelimiterCount, istack, (InlineTag)0, InlineTag.Strikethrough);
                                if (istack.DelimiterCount > 1)
                                {
                                    retry = true;
                                }
                            }
                            else
                            {
                                var useDelims = InlineMethods.MatchInlineStack(iopener, subj, istack.DelimiterCount, istack, InlineTag.Emphasis, InlineTag.Strong);
                                if (istack.DelimiterCount > 0)
                                {
                                    retry = true;
                                }
                            }

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

                                continue;
                            }
                            else
                            {
                                // remove opener, everything in between, and the closer
                                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--;
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Removes a subset of the stack.
        /// </summary>
        /// <param name="first">The first entry to be removed.</param>
        /// <param name="subj">The subject associated with this stack. Can be <see langword="null"/> if the pointers in the subject should not be updated.</param>
        /// <param name="last">The last entry to be removed. Can be <see langword="null"/> if everything starting from <paramref name="first"/> has to be removed.</param>
        public static void RemoveStackEntry(InlineStack first, Subject subj, InlineStack last)
        {
            var curPriority = first.Priority;

            if (last is null)
            {
                if (first.Previous != null)
                {
                    first.Previous.Next = null;
                }
                else if (subj != null)
                {
                    subj.FirstPendingInline = null;
                }

                if (subj != null)
                {
                    last = subj.LastPendingInline;
                    subj.LastPendingInline = first.Previous;
                }

                first = first.Next;
            }
            else
            {
                if (first.Previous != null)
                {
                    first.Previous.Next = last.Next;
                }
                else if (subj != null)
                {
                    subj.FirstPendingInline = last.Next;
                }

                if (last.Next != null)
                {
                    last.Next.Previous = first.Previous;
                }
                else if (subj != null)
                {
                    subj.LastPendingInline = first.Previous;
                }

                if (first == last)
                {
                    return;
                }

                first = first.Next;
                last  = last.Previous;
            }

            if (last is null || first is null)
            {
                return;
            }

            first.Previous = null;
            last.Next      = null;

            // handle case like [*b*] (the whole [..] is being removed but the inner *..* must still be matched).
            // this is not done automatically because the initial * is recognized as a potential closer (assuming
            // potential scenario '*[*' ).
            if (curPriority > 0)
            {
                PostProcessInlineStack(null, first, last, curPriority);
            }
        }