Exemple #1
0
        /// <summary>
        /// Creates a tree of <see cref="InlineSpan"/> from its array.
        /// </summary>
        /// <param name="spans">The array of <see cref="InlineSpan"/>.</param>
        /// <param name="rootLength">The length of the whole text.</param>
        /// <returns>The tree of <see cref="InlineSpan"/> which is equivalent to <paramref name="spans"/>.</returns>
        private static InlineSpan GetInlineTree(SortedList <int, InlineSpan> spans, int rootLength)
        {
            var root = new InlineSpan
            {
                Begin    = 0,
                End      = rootLength,
                SpanType = InlineSpanType.Root,
            };
            InlineSpan currentSpan = root;

            foreach (var item in spans)
            {
                var delimSpan = item.Value;
                while (currentSpan.End < delimSpan.End)
                {
                    currentSpan = currentSpan.Parent ?? throw new Exception();
                }

                currentSpan.Children.Add(delimSpan.Begin, delimSpan);
                delimSpan.Parent = currentSpan;
                currentSpan      = delimSpan;
            }

            return(root);
        }
Exemple #2
0
 void _extractPlaceholderSpans(InlineSpan span)
 {
     _placeholderSpans = new List <PlaceholderSpan>();
     span.visitChildren((InlineSpan inlinespan) => {
         if (inlinespan is PlaceholderSpan)
         {
             PlaceholderSpan placeholderSpan = (PlaceholderSpan)inlinespan;
             _placeholderSpans.Add(placeholderSpan);
         }
         return(true);
     });
 }
Exemple #3
0
        /// <summary>
        /// Converts the specified string and <see cref="InlineSpan"/> tree to inline elements.
        /// </summary>
        /// <param name="text">The string object.</param>
        /// <param name="delim">The <see cref="InlineSpan"/> tree.</param>
        /// <returns>The inline elements which is equivalent to <paramref name="delim"/>.</returns>
        private InlineElement[] ToInlines(string text, InlineSpan delim)
        {
            int lastEnd = delim.ParseBegin;
            List <InlineElement> newChildren = new List <InlineElement>();

            foreach (var item in delim.Children.Where(d => d.Value.End <= delim.ParseEnd))
            {
                InlineSpan delimSpan = item.Value;
                if (lastEnd < delimSpan.Begin)
                {
                    newChildren.AddRange(
                        ParseLineBreak(text.Substring(lastEnd, delimSpan.Begin - lastEnd)));
                }

                newChildren.AddRange(ToInlines(text, delimSpan));
                lastEnd = delimSpan.End;
            }

            if (lastEnd < delim.ParseEnd)
            {
                newChildren.AddRange(
                    ParseLineBreak(text.Substring(lastEnd, delim.ParseEnd - lastEnd)));
            }

            switch (delim.SpanType)
            {
            case InlineSpanType.Link:
                return(new InlineElement[]
                       { new Link(newChildren.ToArray(), delim.Destination, delim.Title, parserConfig) });

            case InlineSpanType.Image:
                return(new InlineElement[]
                       { new Image(newChildren.ToArray(), delim.Destination, delim.Title, parserConfig) });

            case InlineSpanType.Emphasis:
                return(new InlineElement[] { new Emphasis(newChildren.ToArray(), false, parserConfig) });

            case InlineSpanType.StrongEmphasis:
                return(new InlineElement[] { new Emphasis(newChildren.ToArray(), true, parserConfig) });

            case InlineSpanType.Root:
                return(newChildren.ToArray());

            default:
                return(new[] { delim.DelimElem });
            }
        }
Exemple #4
0
        public override RenderComparison compareTo(InlineSpan other)
        {
            if (this == other)
            {
                return(RenderComparison.identical);
            }
            if (other.GetType() != GetType())
            {
                return(RenderComparison.layout);
            }
            if ((style == null) != (other.style == null))
            {
                return(RenderComparison.layout);
            }
            WidgetSpan typedOther = other as WidgetSpan;

            if (!child.Equals(typedOther.child) || alignment != typedOther.alignment)
            {
                return(RenderComparison.layout);
            }

            RenderComparison result = RenderComparison.identical;

            if (style != null)
            {
                RenderComparison candidate = style.compareTo(other.style);
                if ((int)candidate > (int)result)
                {
                    result = candidate;
                }
                if (result == RenderComparison.layout)
                {
                    return(result);
                }
            }

            return(result);
        }
Exemple #5
0
        public override void handleEvent(PointerEvent evt, HitTestEntry entry)
        {
            D.assert(debugHandleEvent(evt, entry));
            if (!(evt is PointerDownEvent))
            {
                return;
            }

            _layoutTextWithConstraints(constraints);
            Offset       offset   = ((BoxHitTestEntry)entry).localPosition;
            TextPosition position = _textPainter.getPositionForOffset(offset);
            InlineSpan   span     = _textPainter.text.getSpanForPosition(position);

            if (span == null)
            {
                return;
            }
            if (span is TextSpan)
            {
                TextSpan textSpan = (TextSpan)span;
                textSpan.recognizer?.addPointer(evt as PointerDownEvent);
            }
        }
Exemple #6
0
 public RenderParagraph(
     InlineSpan text             = null,
     TextAlign textAlign         = TextAlign.start,
     TextDirection textDirection = TextDirection.ltr,
     bool softWrap                            = true,
     TextOverflow overflow                    = TextOverflow.clip,
     float textScaleFactor                    = 1.0f,
     int?maxLines                             = null,
     Locale locale                            = null,
     StrutStyle strutStyle                    = null,
     TextWidthBasis textWidthBasis            = TextWidthBasis.parent,
     ui.TextHeightBehavior textHeightBehavior = null,
     List <RenderBox> children                = null
     )
 {
     D.assert(maxLines == null || maxLines > 0);
     D.assert(text != null);
     D.assert(text.debugAssertIsValid());
     D.assert(maxLines == null || maxLines > 0);
     _softWrap    = softWrap;
     _overflow    = overflow;
     _textPainter = new TextPainter(
         text: text,
         textAlign: textAlign,
         textDirection: textDirection,
         textScaleFactor: textScaleFactor,
         maxLines: maxLines,
         ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null,
         locale: locale,
         strutStyle: strutStyle,
         textWidthBasis: textWidthBasis,
         textHeightBehavior: textHeightBehavior
         );
     addAll(children);
     _extractPlaceholderSpans(text);
 }
Exemple #7
0
        /// <summary>
        /// Parses inline elements and returns them.
        /// </summary>
        /// <param name="text">The text to parse.</param>
        /// <returns>Inline elements in <paramref name="text"/>.</returns>
        public IEnumerable <InlineElement> ParseInlineElements(string text)
        {
            var highPriorityDelims = new List <InlineSpan>();
            int currentIndex       = 0;
            int nextBacktick       = GetNextUnescaped(text, '`', 0);
            int nextLessThan       = GetNextUnescaped(text, '<', 0);

            // Extract code spans, raw html and auto links.
            while (currentIndex < text.Length)
            {
                int           newIndex;
                int           nextElemIndex;
                InlineElement newInline;

                // Find `
                // Search code span
                if (nextBacktick >= 0 && (nextLessThan < 0 || nextBacktick < nextLessThan))
                {
                    nextElemIndex = nextBacktick;
                    newIndex      = nextElemIndex;
                    newInline     = GetCodeSpan(text, nextBacktick, ref newIndex);
                }
                // Find <
                // Search raw html and auto links
                else if (nextLessThan >= 0 && (nextBacktick < 0 || nextLessThan < nextBacktick))
                {
                    nextElemIndex = nextLessThan;
                    newIndex      = nextElemIndex;
                    newInline     = GetInlineHtmlOrLink(text, nextLessThan, ref newIndex);
                }
                else // Find neither ` nor <
                {
                    // End Searching
                    break;
                }

                if (newInline != null)
                {
                    var span = new InlineSpan
                    {
                        Begin     = nextElemIndex,
                        End       = newIndex,
                        SpanType  = ToDelimType(newInline.Type),
                        DelimElem = newInline,
                    };
                    highPriorityDelims.Add(span);

                    currentIndex = newIndex;
                    nextBacktick = GetNextUnescaped(text, '`', currentIndex);
                    nextLessThan = GetNextUnescaped(text, '<', currentIndex);
                }
                else
                {
                    nextElemIndex += CountSameChars(text, nextElemIndex);
                    nextBacktick   = GetNextUnescaped(text, '`', nextElemIndex);
                    nextLessThan   = GetNextUnescaped(text, '<', nextElemIndex);
                }
            }

            return(ParseLinkEmphasis(text, highPriorityDelims));
        }
Exemple #8
0
        /// <summary>
        /// Parses the structure and add the <see cref="InlineSpan"/> to <paramref name="delimSpans"/>.
        /// </summary>
        /// <param name="deliminators">The list of <see cref="DeliminatorInfo"/>.</param>
        /// <param name="delimSpans">The list of <see cref="InlineSpan"/>.</param>
        /// <param name="stackBottom">The stack bottom.</param>
        private static void ParseEmphasis(LinkedList <DeliminatorInfo> deliminators,
                                          SortedList <int, InlineSpan> delimSpans, DeliminatorInfo stackBottom)
        {
            if (deliminators.Count == 0)
            {
                return;
            }

            LinkedListNode <DeliminatorInfo> firstClose = null;
            LinkedListNode <DeliminatorInfo> infoNode   =
                stackBottom == null ? deliminators.First : deliminators.Find(stackBottom);

            while (infoNode != null)
            {
                if (infoNode.Value.CanClose)
                {
                    firstClose = infoNode;
                    break;
                }

                infoNode = infoNode.Next;
            }

            if (firstClose == null)
            {
                return;
            }

            LinkedListNode <DeliminatorInfo> startDelimNode = null;

            infoNode = firstClose;
            while ((infoNode = infoNode.Previous) != null && infoNode.Value != stackBottom)
            {
                if (infoNode.Value.CanOpen &&
                    infoNode.Value.Type == firstClose.Value.Type &&
                    ((infoNode.Value.DeliminatorLength + firstClose.Value.DeliminatorLength) % 3 != 0 ||
                     infoNode.Value.DeliminatorLength % 3 == 0 ||
                     (!firstClose.Value.CanOpen && !infoNode.Value.CanClose)))
                {
                    startDelimNode = infoNode;
                    break;
                }
            }

            if (startDelimNode == null)
            {
                if (!firstClose.Value.CanOpen)
                {
                    deliminators.Remove(firstClose);
                }

                firstClose = firstClose.Next;
                if (firstClose == null)
                {
                    return;
                }

                ParseEmphasis(deliminators, delimSpans, firstClose.Value);
                return;
            }

            DeliminatorInfo openInfo    = startDelimNode.Value;
            DeliminatorInfo closeInfo   = firstClose.Value;
            int             delimLength = openInfo.DeliminatorLength > 1 && closeInfo.DeliminatorLength > 1 ? 2 : 1;
            var             delimSpan   = new InlineSpan
            {
                Begin    = openInfo.Index + openInfo.DeliminatorLength - delimLength,
                End      = closeInfo.Index + delimLength,
                SpanType =
                    delimLength > 1 ? InlineSpanType.StrongEmphasis : InlineSpanType.Emphasis,
            };

            delimSpan.ParseBegin = delimSpan.Begin + delimLength;
            delimSpan.ParseEnd   = delimSpan.End - delimLength;
            delimSpans.Add(delimSpan.Begin, delimSpan);
            while ((infoNode = infoNode.Next) != null && infoNode != firstClose)
            {
                deliminators.Remove(infoNode);
            }

            openInfo.DeliminatorLength -= delimLength;
            if (openInfo.DeliminatorLength <= 0)
            {
                deliminators.Remove(openInfo);
            }

            closeInfo.DeliminatorLength -= delimLength;
            closeInfo.Index             += delimLength;
            if (closeInfo.DeliminatorLength <= 0)
            {
                deliminators.Remove(closeInfo);
            }

            ParseEmphasis(deliminators, delimSpans,
                          deliminators.Find(firstClose.Value) == null ? firstClose.Next?.Value : firstClose.Value);
        }
Exemple #9
0
        /// <summary>
        /// Parses inline elements to Links, Images Emphasis and Line breaks.
        /// </summary>
        /// <param name="text">The string object to @arse.</param>
        /// <param name="higherSpans">Delim Spans which represents higher priority.</param>
        /// <returns>The parse result.</returns>
        private IEnumerable <InlineElement> ParseLinkEmphasis(string text, List <InlineSpan> higherSpans)
        {
            var deliminators = new LinkedList <DeliminatorInfo>();
            var inlineSpans  = new SortedList <int, InlineSpan>();

            for (int i = 0; i < text.Length; i++)
            {
                // If the character is escaped or contained in higherSpans
                if (IsEscaped(text, i) || higherSpans.Any(d => d.Begin <= i && d.End > i))
                {
                    continue;
                }

                if (text[i] == '*')
                {
                    int length    = CountSameChars(text, i);
                    var delimInfo = DeliminatorInfo.Create(DeliminatorType.Star, i, length);
                    delimInfo.CanOpen  = IsLeftFlanking(text, delimInfo);
                    delimInfo.CanClose = IsRightFlanking(text, delimInfo);

                    deliminators.AddLast(delimInfo);
                    i += length - 1;
                }
                else if (text[i] == '_')
                {
                    int  length        = CountSameChars(text, i);
                    var  delimInfo     = DeliminatorInfo.Create(DeliminatorType.UnderBar, i, length);
                    bool leftFranking  = IsLeftFlanking(text, delimInfo);
                    bool rightFlanking = IsRightFlanking(text, delimInfo);

                    delimInfo.CanOpen  = leftFranking && (!rightFlanking || IsPrecededByPunctuation(text, delimInfo));
                    delimInfo.CanClose = rightFlanking && (!leftFranking || IsFollowedByPunctuation(text, delimInfo));
                    deliminators.AddLast(delimInfo);
                    i += length - 1;
                }
                else if (text[i] == '[')
                {
                    deliminators.AddLast(DeliminatorInfo.Create(DeliminatorType.OpenLink, i, 1));
                }
                else if (BeginWith(text, i, "!["))
                {
                    deliminators.AddLast(DeliminatorInfo.Create(DeliminatorType.OpenImage, i, 2));
                    i++;
                }
                else if (i > 0 && text[i] == ']')
                {
                    DeliminatorInfo openInfo = deliminators
                                               .LastOrDefault(info => info.Type == DeliminatorType.OpenImage ||
                                                              info.Type == DeliminatorType.OpenLink);
                    if (openInfo == null)
                    {
                        continue;
                    }

                    if (!openInfo.Active)
                    {
                        deliminators.Remove(openInfo);
                        continue;
                    }

                    int linkLabel  = GetStartIndexOfLinkLabel(text, 0, i + 1, higherSpans);
                    int linkBody   = GetLinkBodyEndIndex(text, i + 1, out var dest, out var title);
                    int linkLabel2 = GetEndIndexOfLinkLabel(text, i + 1, higherSpans);

                    // Inline Link/Image
                    if (text[Math.Min(i + 1, text.Length - 1)] == '(' && linkLabel >= 0 && linkBody >= 0)
                    {
                        inlineSpans.Add(openInfo.Index,
                                        InlineSpan.FromDeliminatorInfo(openInfo, linkBody, i, dest ?? string.Empty, title));
                        i = linkBody - 1;
                    }
                    // Collapsed Reference Link
                    else if (BeginWith(text, i + 1, "[]") &&
                             TryGetReference(text.Substring(openInfo.Index + openInfo.DeliminatorLength,
                                                            i - openInfo.Index - openInfo.DeliminatorLength), out var definition))
                    {
                        inlineSpans.Add(openInfo.Index, InlineSpan.FromDeliminatorInfo(openInfo, i + 3, i, definition));
                        i += 2;
                    }
                    // Full Reference Link
                    else if (linkLabel2 >= 0 &&
                             TryGetReference(text.Substring(i + 2, linkLabel2 - i - 3), out definition))
                    {
                        inlineSpans.Add(openInfo.Index,
                                        InlineSpan.FromDeliminatorInfo(openInfo, linkLabel2, i, definition));
                        i = linkLabel2 - 1;
                    }
                    // shortcut link
                    else if (TryGetReference(text.Substring(openInfo.Index + openInfo.DeliminatorLength,
                                                            i - openInfo.Index - openInfo.DeliminatorLength), out definition) &&
                             GetEndIndexOfLinkLabel(text, i + 1, higherSpans) < 0)
                    {
                        inlineSpans.Add(openInfo.Index, InlineSpan.FromDeliminatorInfo(openInfo, i + 1, i, definition));
                    }
                    else
                    {
                        deliminators.Remove(openInfo);
                        continue;
                    }

                    if (openInfo.Type == DeliminatorType.OpenLink)
                    {
                        foreach (var item in deliminators.TakeWhile(c => c != openInfo))
                        {
                            if (item.Type == DeliminatorType.OpenLink)
                            {
                                item.Active = false;
                            }
                        }
                    }

                    ParseEmphasis(deliminators, inlineSpans, openInfo);
                    deliminators.Remove(openInfo);
                }
            }

            ParseEmphasis(deliminators, inlineSpans, null);

            foreach (var item in higherSpans)
            {
                inlineSpans.Add(item.Begin, item);
            }

            var tree = GetInlineTree(inlineSpans, text.Length);

            return(ToInlines(text, tree));
        }