Esempio n. 1
0
    public void Parse(string richText, out List <RichTextTag> tags)
    {
        tagParserStack.Clear();
        tagList.Clear();
        Match match = regex.Match(richText);

        while (match.Success)
        {
            if (match.Value == endStr)
            {
                if (tagParserStack.Count > 0)
                {
                    RichTextTagParser tagParser = tagParserStack.Pop();
                    tagParser.end = match.Index - 1;
                    if (tagParser.end >= tagParser.start)
                    {
                        RichTextTag tag = tagParser.Parse();
                        if (tag != null)
                        {
                            tagList.Add(tag);
                        }
                    }
                }
            }
            else
            {
                RichTextTagParser tagParser = new RichTextTagParser();
                tagParser.content = match.Value;
                tagParser.start   = match.Index + match.Length;
                tagParserStack.Push(tagParser);
            }
            match = match.NextMatch();
        }
        tags = tagList;
    }
Esempio n. 2
0
 private void LogTag(RichTextTag tag)
 {
     if (tag != null)
     {
         Debug.Log("Tag: " + tag.ToString());
     }
 }
Esempio n. 3
0
    /// <summary>
    /// 根据字符串创建文本标记
    /// </summary>
    /// <param name="_text"></param>
    /// <returns></returns>
    private static void CreateSymbolsFromText(string _text)
    {
        int textSymbolIndex  = 0;
        int parsedCharacters = 0;

        while (parsedCharacters < _text.Length)
        {
            TextSymbol symbol = null;

            // 检查富文本标签
            var remainingText = _text.Substring(parsedCharacters, _text.Length - parsedCharacters);
            if (RichTextTag.StringStartsWithTag(remainingText))
            {
                var tag = RichTextTag.ParseNext(remainingText);
                if (null != tag)
                {
                    // 富文本标签的文本标记
                    symbol     = GetTextSymbol(textSymbolIndex++);
                    symbol.Tag = tag;
                }
            }

            if (null == symbol)
            {
                // 普通字符的文本标记
                symbol           = GetTextSymbol(textSymbolIndex++);
                symbol.Character = remainingText.Substring(0, 1);
            }

            parsedCharacters += symbol.Length;
        }

        m_ValidTextSymbolCount = textSymbolIndex;
    }
    private static List <TypedTextSymbol> CreateSymbolListFromText(string text)
    {
        var symbolList       = new List <TypedTextSymbol>();
        int parsedCharacters = 0;

        while (parsedCharacters < text.Length)
        {
            TypedTextSymbol symbol = null;

            // Check for tags
            var remainingText = text.Substring(parsedCharacters, text.Length - parsedCharacters);
            if (RichTextTag.StringStartsWithTag(remainingText))
            {
                var tag = RichTextTag.ParseNext(remainingText);
                symbol = new TypedTextSymbol(tag);
            }
            else
            {
                symbol = new TypedTextSymbol(remainingText.Substring(0, 1));
            }

            parsedCharacters += symbol.Length;
            symbolList.Add(symbol);
        }

        return(symbolList);
    }
Esempio n. 5
0
    private void ReportInitialHighlightError(int index, string text, string foundDescriptor, string expectedDescriptor, ResearchEncyclopediaArticleConfig config)
    {
        // Set the start index either to the beginning of the string
        // or ten less than index, whichever is bigger
        int startIndex = Mathf.Max(0, index - 20);
        // Set length to 20 or the difference between the start index
        // and end of string, whichever is smaller
        int length = Mathf.Min(40, text.Length - startIndex);
        // Get the substring of the text
        string reportString = text.Substring(startIndex, length);

        // Apply the color red to the part of the tag that is invalid
        RichTextTag invalidBraceTag = new RichTextTag("color", "red");

        reportString = invalidBraceTag.Apply(reportString, index - startIndex, 1);

        // Add ellipses if this is not the start or end of the whole string
        if (startIndex > 0)
        {
            reportString = "..." + reportString;
        }
        if (startIndex + length < text.Length)
        {
            reportString += "...";
        }

        // Add double quotes around the report string
        reportString  = "\"" + reportString;
        reportString += "\"";

        Debug.LogWarning("Found " + foundDescriptor + " where " + expectedDescriptor + " was expected\n" +
                         "\tArticle: " + config.ID.ToString() + "\n" +
                         "\tPosition: " + reportString + "\n");
    }
Esempio n. 6
0
        public static IEnumerable <RichText> ParseRichText(string richText, bool insideCodeBlock = false)
        {
                        #if VERBOSE_DEBUGGING
            Debug.Log($"Began Parsing: {richText}");
                        #endif

            List <RichText> resultantRichText = new List <RichText>();

            RichTextTag         currentRichTextTag   = default;
            Stack <RichTextTag> previousRichTextTags = new Stack <RichTextTag>();
            int currentIndex = 0;
            int length       = richText.Length;
            int lastNewTag   = 0;

            //Loop through the whole string
            while (currentIndex < length)
            {
                int currentSearchingIndex = currentIndex;
                //Looking to discover a valid starting delimiter
                //indexOfOpening is the index of the character after the opening <
                int  indexOfOpening = currentSearchingIndex;
                bool discoveredValidStartingDelimiter = false;
                while (!discoveredValidStartingDelimiter)
                {
                    switch (DiscoverValidStartingDelimiter(out indexOfOpening))
                    {
                    case Discovery.Invalid:
                        continue;

                    case Discovery.Valid:
                        break;

                    case Discovery.End:
                        Exit();
                        return(resultantRichText);

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    currentSearchingIndex = indexOfOpening + 1;
                }

                //Now we have the index of a possible starting delimiter look for the ending delimiter.
                int indexOfClosing = richText.IndexOf(closingTagDelimiter, currentSearchingIndex);
                if (indexOfClosing < 0)
                {
                    Exit();
                    return(resultantRichText);
                }

                //Make sure that that closing delimiter doesn't have an opening delimiter behind it.
                while (true)
                {
                    switch (DiscoverValidStartingDelimiter(out int indexOfNextOpening, indexOfClosing - currentSearchingIndex))
                    {
    private static string RemoveCustomTags(string textWithTags)
    {
        string textWithoutTags = textWithTags;

        foreach (var customTag in CustomTagTypes)
        {
            textWithoutTags = RichTextTag.RemoveTagsFromString(textWithoutTags, customTag);
        }

        return(textWithoutTags);
    }
Esempio n. 8
0
    /// <summary>
    /// 从字符串中移除富文本标签
    /// </summary>
    /// <param name="_textWithTags"></param>
    /// <param name="_tags"></param>
    /// <returns></returns>
    private static string RemoveTags(string _textWithTags, string[] _tags)
    {
        var textWithoutTags = _textWithTags;

        foreach (var tag in _tags)
        {
            textWithoutTags = RichTextTag.RemoveTagsFromString(textWithoutTags, tag);
        }

        return(textWithoutTags);
    }
    private static string RemoveUnityTags(string textWithTags)
    {
        string textWithoutTags = textWithTags;

        foreach (var unityTag in UnityTagTypes)
        {
            textWithoutTags = RichTextTag.RemoveTagsFromString(textWithoutTags, unityTag);
        }

        return(textWithoutTags);
    }
Esempio n. 10
0
        public void Constructor_OpeningTag_Parses()
        {
            //Arrange
            var tag = "<b>";

            //Act
            var richTextTag = new RichTextTag(tag);

            //Assert
            Assert.AreEqual(tag, richTextTag.TagText);
            Assert.AreEqual("b", richTextTag.TagType);
            Assert.IsFalse(richTextTag.IsClosingTag);
            Assert.AreEqual("</b>", richTextTag.ClosingTagText);
            Assert.AreEqual(string.Empty, richTextTag.Parameter);
        }
Esempio n. 11
0
        public void Constructor_TagAndParameterWithQuotes_Parses()
        {
            //Arrange
            var tag = "<color=\"red\">";

            //Act
            var richTextTag = new RichTextTag(tag);

            //Assert
            Assert.AreEqual(tag, richTextTag.TagText);
            Assert.AreEqual("color", richTextTag.TagType);
            Assert.IsFalse(richTextTag.IsClosingTag);
            Assert.AreEqual("</color>", richTextTag.ClosingTagText);
            Assert.AreEqual("red", richTextTag.Parameter);
        }
 public void Update()
 {
     if (Input.GetKeyDown(KeyCode.Tilde))
     {
         var tag = RichTextTag.ParseNext("blah<color=red>boo</color");
         LogTag(tag);
         tag = RichTextTag.ParseNext("<color=blue>blue</color");
         LogTag(tag);
         tag = RichTextTag.ParseNext("No tag in here");
         LogTag(tag);
         tag = RichTextTag.ParseNext("No <color=blueblue</color tag here either");
         LogTag(tag);
         tag = RichTextTag.ParseNext("This tag is a closing tag </bold>");
         LogTag(tag);
     }
     if (Input.GetKeyDown(KeyCode.Space))
     {
         HandlePrintNextClicked();
     }
 }
    public string RichEncyclopediaArticleText()
    {
        string richText         = articleConfig.Text;
        int    indexAdjuster    = 0; // Adjust the index for each highlight
        int    indexIncrementer = 0; // Length of all the tags used in each highlight

        // Compute the index incrementer by incrementing tag lengths
        foreach (RichTextTag tag in highlightTags)
        {
            indexIncrementer += tag.Length;
        }
        // Go through all highlights
        foreach (TextHighlight highlight in articleData.Highlights)
        {
            richText = RichTextTag.ApplyMultiple(highlightTags, richText, highlight.Start + indexAdjuster, highlight.Length);
            // Increase the global index adjuster
            indexAdjuster += indexIncrementer;
        }

        return(richText);
    }
Esempio n. 14
0
    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.Tilde))
        {
            var tag = RichTextTag.ParseNext("blah<color=red>boo</color");
            LogTag(tag);
            tag = RichTextTag.ParseNext("<color=blue>blue</color");
            LogTag(tag);
            tag = RichTextTag.ParseNext("No tag in here");
            LogTag(tag);
            tag = RichTextTag.ParseNext("No <color=blueblue</color tag here either");
            LogTag(tag);
            tag = RichTextTag.ParseNext("This tag is a closing tag </bold>");
            LogTag(tag);
        }

        if (Input.GetButtonUp("Shoot") || Input.GetButtonUp("Use"))
        {
            HandlePrintNextClicked();
        }

        if (choiceButtons[0].IsActive() && initializeButtonChoice == false)
        {
            if (Input.GetButtonUp("MoveLeft"))
            {
                choiceButtons[0].FindSelectableOnLeft();
                initializeButtonChoice = true;
            }
            else if (Input.GetButtonUp("MoveRight"))
            {
                choiceButtons[0].FindSelectableOnRight();
                initializeButtonChoice = true;
            }
            else if (Input.GetButtonUp("Shoot") || Input.GetButtonUp("Use"))
            {
                choiceButtons[0].Select();
                initializeButtonChoice = true;
            }
        }
    }
Esempio n. 15
0
    public RichTextTag Parse()
    {
        RichTextTag tag   = null;
        Match       match = tagRegex.Match(content);

        if (match.Success)
        {
            string tagName = match.Groups[1].Value;//标签类型
            if (!tagName.StartsWith("#"))
            {
                var keyValueCollection = paraRegex.Matches(match.Groups[2].Value);//标签参数
                switch (tagName)
                {
                case "underline":
                {
                    tag = new RichTextUnderlineTag();
                    break;
                }

                default:
                    break;
                }
                if (tag != null)
                {
                    tag.start = start;
                    tag.end   = end;
                    for (int i = 0; i < keyValueCollection.Count; i++)
                    {
                        string key   = keyValueCollection[i].Groups[1].Value;
                        string value = keyValueCollection[i].Groups[2].Value;
                        tag.SetValue(key, value);
                    }
                }
            }
        }
        return(tag);
    }
Esempio n. 16
0
        public static IEnumerable <RichText> ParseRichText(string richText, bool insideCodeBlock = false)
        {
                        #if VERBOSE_DEBUGGING
            Debug.Log($"Began Parsing: {richText}");
                        #endif

            List <RichText> resultantRichText = new List <RichText>();

            RichTextTag         currentRichTextTag   = default;
            Stack <RichTextTag> previousRichTextTags = new Stack <RichTextTag>();
            int currentIndex = 0;
            int length       = richText.Length;
            int lastNewTag   = 0;

            //Loop through the whole string
            while (currentIndex < length)
            {
                int currentSearchingIndex = currentIndex;
                //Looking to discover a valid starting delimiter
                //indexOfOpening is the index of the character after the opening <
                int  indexOfOpening = currentSearchingIndex;
                bool discoveredValidStartingDelimiter = false;
                while (!discoveredValidStartingDelimiter)
                {
                    switch (DiscoverValidStartingDelimiter(out indexOfOpening))
                    {
                    case Discovery.Invalid:
                        continue;

                    case Discovery.Valid:
                        break;

                    case Discovery.End:
                        Exit();
                        return(resultantRichText);

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    currentSearchingIndex = indexOfOpening + 1;
                }

                //Now we have the index of a possible starting delimiter look for the ending delimiter.
                int indexOfClosing = richText.IndexOf(closingTagDelimiter, currentSearchingIndex);
                if (indexOfClosing < 0)
                {
                    Exit();
                    return(resultantRichText);
                }

                //Make sure that that closing delimiter doesn't have an opening delimiter behind it.
                while (true)
                {
                    var val = DiscoverValidStartingDelimiter(out int indexOfNextOpening, indexOfClosing - currentSearchingIndex);
                    switch (val)
                    {
                    case Discovery.Invalid:
                        continue;

                    case Discovery.Valid:
                        if (insideCodeBlock)
                        {
                            break;
                        }
                        Debug.LogError(
                            $"Text parsed by {nameof(RichTextParser)} has two un-escaped opening delimiters: \"{openingTagDelimiter}\" at {currentSearchingIndex} & {indexOfNextOpening}. {NotParsedError()}");
                        Exit();
                        return(resultantRichText);

                    case Discovery.End:
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;
                }

                //Get the location of the starting delimiter if it exists.
                //search index returned is the index after the start delimiter.
                Discovery DiscoverValidStartingDelimiter(out int searchIndex, int count = -1)
                {
                    searchIndex = currentSearchingIndex;
                    int indexOfOpeningDelimiter = count < 0
                                                ? richText.IndexOf(openingTagDelimiter, currentSearchingIndex)
                                                : richText.IndexOf(openingTagDelimiter, currentSearchingIndex, count);

                    if (indexOfOpeningDelimiter < 0)
                    {
                        return(Discovery.End);
                    }

                    if (indexOfOpeningDelimiter - 1 > 0)
                    {
                        //if the text behind the opening tag is not the escape character then the tag must be valid.
                        if (!richText[indexOfOpeningDelimiter - 1].Equals(escapeCharacter))
                        {
                            /*//Unless it's a space,
                             * && indexOfOpeningDelimiter + 1 < richText.Length && richText[indexOfOpeningDelimiter + 1] != ' '
                             * //Or a numerical character.
                             * && (richText[indexOfOpeningDelimiter + 1] < 48 || 57 < richText[indexOfOpeningDelimiter + 1])*/

                            discoveredValidStartingDelimiter = true;
                        }
                    }
                    else
                    {
                        //if there is no characters behind the opening tag it must be valid.
                        discoveredValidStartingDelimiter = true;
                    }

                    searchIndex = indexOfOpeningDelimiter + 1;
                    return(discoveredValidStartingDelimiter ? Discovery.Valid : Discovery.Invalid);
                }

                string resultantTag = richText.Substring(indexOfOpening, indexOfClosing - indexOfOpening);

                bool successfullyParsedTag = true;

                if (insideCodeBlock)
                {
                    if (ParseForSpan(resultantTag, out string styleClass))
                    {
                        AddLastTextWithRichTextTag(currentRichTextTag);
                        currentRichTextTag = currentRichTextTag.GetWithSpan(styleClass);
                    }
                    else if (resultantTag.Equals("/span"))
                    {
                        AddLastTextWithRichTextTag(currentRichTextTag, false);
                        currentRichTextTag = currentRichTextTag.GetWithRemovedSpan();
                        RemoveTag();
                    }
                    else
                    {
                        successfullyParsedTag = false;
                    }
                }
                else
                {
                    if (currentRichTextTag.tag == Tag.code)
                    {
                        //When inside the a code tag we ignore all tags except the closing of a code tag.
                        if (resultantTag.Equals("/code"))
                        {
                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            currentRichTextTag = default;
                            ClearTags();
                        }
                        else
                        {
                            //Continue parsing, looking for that closing code tag.
                            currentIndex = indexOfOpening;
                            continue;
                        }
                    }
                    else
                    {
                        //Switch through tags that are entire strings
                        switch (resultantTag)
                        {
                        case "/":                                 //Exit Tag
                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            RemoveTag(true);
                            break;

                        case "b":                                 //Start Bold
                            AddLastTextWithRichTextTag(currentRichTextTag);
                            currentRichTextTag = currentRichTextTag.GetWithAddedBold();
                            break;

                        case "/b":                                 //End Bold
                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            currentRichTextTag = currentRichTextTag.GetWithRemovedBold();
                            RemoveTag();
                            break;

                        case "i":                                 //Start Italics
                            AddLastTextWithRichTextTag(currentRichTextTag);
                            currentRichTextTag = currentRichTextTag.GetWithAddedItalics();
                            break;

                        case "/i":                                 //End Italics
                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            currentRichTextTag = currentRichTextTag.GetWithRemovedItalics();
                            RemoveTag();
                            break;

                        case "code":                                 //Start Code
                            if (!currentRichTextTag.Equals(default(RichTextTag)))
                            {
                                Debug.LogError($"Rich Text entered a Code tag without closing prior tags. This is not allowed. {NotParsedError()}");
                                RichTextDebug();
                                Exit();
                                return(resultantRichText);
                            }

                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            currentRichTextTag = new RichTextTag(Tag.code, FontStyle.Normal, Color.clear, 0, null);
                            ClearTags();
                            break;

                        case "/code":                                 //End Code but if not already in a code block.
                            if (currentRichTextTag.tag != Tag.code)
                            {
                                Debug.LogError($"Code tag was exited without being in a code block. {NotParsedError()}");
                                RichTextDebugHighlit(indexOfOpening, indexOfClosing);
                                Exit();
                                return(resultantRichText);
                            }

                            break;

                        case "/button":                                 //End Button
                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            currentRichTextTag = currentRichTextTag.GetWithRemovedButton();
                            RemoveTag();
                            break;

                        case "/color":                                 //End Colour
                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            currentRichTextTag = currentRichTextTag.GetWithRemovedColor();
                            RemoveTag();
                            break;

                        case "/span":                                 //End Span
                            AddLastTextWithRichTextTag(currentRichTextTag, false);
                            currentRichTextTag = currentRichTextTag.GetWithRemovedSpan();
                            RemoveTag();
                            break;

                        default:
                            successfullyParsedTag = false;
                            break;
                        }

                        //StartsWith cannot be in the above switch.
                        if (!successfullyParsedTag)
                        {
                            successfullyParsedTag = true;
                            if (resultantTag.StartsWith("size"))                             //START SIZE
                            {
                                if (!GetStringVariables("size", out string stringVariables))
                                {
                                    continue;
                                }
                                if (!int.TryParse(stringVariables, out int size))
                                {
                                    Debug.Log($"Size tag \"{resultantTag}\" does not contain a parseable integer. \"{stringVariables}\"");
                                    RichTextDebugHighlit(indexOfOpening, indexOfClosing);
                                }
                                else
                                {
                                    AddLastTextWithRichTextTag(currentRichTextTag);
                                    currentRichTextTag = currentRichTextTag.GetWithNewSize(size);
                                }
                            }
                            else if (resultantTag.StartsWith("button"))                             //START BUTTON
                            {
                                if (!GetStringVariables("button", out string stringVariables))
                                {
                                    continue;
                                }
                                if (string.IsNullOrEmpty(stringVariables))
                                {
                                    Debug.Log($"Button tag \"{resultantTag}\" does not contain a key. \"{stringVariables}\"");
                                    RichTextDebugHighlit(indexOfOpening, indexOfClosing);
                                }
                                else
                                {
                                    AddLastTextWithRichTextTag(currentRichTextTag);
                                    currentRichTextTag = currentRichTextTag.GetWithButton(stringVariables);
                                }
                            }
                            else if (resultantTag.StartsWith("color"))                             //START COLOR
                            {
                                if (!GetStringVariables("color", out string stringVariables))
                                {
                                    continue;
                                }
                                if (!ColorUtility.TryParseHtmlString(stringVariables, out Color colour))
                                {
                                    Debug.Log($"Color tag \"{resultantTag}\" does not contain a HTML colour. \"{stringVariables}\"");
                                    RichTextDebugHighlit(indexOfOpening, indexOfClosing);
                                }
                                else
                                {
                                    AddLastTextWithRichTextTag(currentRichTextTag);
                                    currentRichTextTag = currentRichTextTag.GetWithNewColor(colour);
                                }
                            }
                            else if (ParseForSpan(resultantTag, out string styleClass))
                            {
                                AddLastTextWithRichTextTag(currentRichTextTag);
                                currentRichTextTag = currentRichTextTag.GetWithSpan(styleClass);
                            }
                            else
                            {
                                successfullyParsedTag = false;
                            }
                        }
                    }

                    //Gets the plain string variables following a tag.
                    bool GetStringVariables(string tag, out string stringVariables)
                    {
                        stringVariables = null;
                        int indexOfEquals = resultantTag.IndexOf('=', tag.Length);

                        if (indexOfEquals < 0)
                        {
                            Debug.Log($"{tag} tag \"{resultantTag}\" does not contain an = and variables.");
                            RichTextDebugHighlit(indexOfOpening, indexOfClosing);
                            return(false);
                        }

                        stringVariables = resultantTag.Substring(indexOfEquals + 1).Replace(" ", string.Empty);
                        return(true);
                    }
                }

                void RemoveTag(bool assignTag = false)
                {
                    if (previousRichTextTags.Count == 0)
                    {
                        Debug.LogError(
                            $"No Tags to Pop! Last added text: {(resultantRichText.Count > 0 ? $"{resultantRichText[resultantRichText.Count - 1].richTextTag.ToString()} | {resultantRichText[resultantRichText.Count - 1].associatedText}" : "none")}");
                        return;
                    }

                    if (assignTag)
                    {
                        currentRichTextTag = previousRichTextTags.Pop();
                    }
                    else
                    {
                        previousRichTextTags.Pop();
                    }
                }

                void AddTag() => previousRichTextTags.Push(currentRichTextTag);

                void ClearTags() => previousRichTextTags.Clear();

                void AddLastTextWithRichTextTag(RichTextTag tag, bool addTag = true)
                {
                    if (addTag)
                    {
                        AddTag();
                    }

                    //Don't add if no text content to add.
                    if (lastNewTag == indexOfOpening - 1)
                    {
                        return;
                    }

                    string text = richText.Substring(lastNewTag, (indexOfOpening - 1) - lastNewTag);

                                        #if VERBOSE_DEBUGGING
                    Debug.Log($"Added Text: \"{text}\".");
                                        #endif

                    resultantRichText.Add(new RichText(tag, text));
                }

                if (successfullyParsedTag)
                {
                                        #if VERBOSE_DEBUGGING
                    Debug.Log($"<color=green>{GetRichTextCapableText($"<{resultantTag}>")}</color>");
                                        #endif
                    currentIndex = indexOfClosing + 1;
                    lastNewTag   = currentIndex;
                }
                else
                {
                                        #if VERBOSE_DEBUGGING
                    Debug.Log($"<color=red>{GetRichTextCapableText($"<{resultantTag}>")}</color>");
                                        #endif
                    currentIndex = indexOfOpening;
                }

                string NotParsedError() => "This text has not been parsed beyond this point.";
                void RichTextDebug() => Debug.Log(richText);

                void RichTextDebugHighlit(int highlightStart, int highlightEnd) => Debug.LogWarning(
                    $"{GetRichTextCapableText(richText.Substring(0, highlightStart))}<color=red>{GetRichTextCapableText(richText.Substring(highlightStart, highlightEnd - highlightStart))}</color>{GetRichTextCapableText(richText.Substring(highlightEnd))}")
                ;

                string GetRichTextCapableText(string text) => text.Replace("<", "<<b></b>");
            }


            Exit();
            return(resultantRichText);

            void Exit() => resultantRichText.Add(new RichText(currentRichTextTag, richText.Substring(lastNewTag)));
        }
 public TypedTextSymbol(RichTextTag tag)
 {
     this.Tag = tag;
 }
    /// <summary>
    /// Gets the typed text at the specified visibleCharacterIndex. This is the text that should be written
    /// to the Text component.
    /// </summary>
    /// <returns>The <see cref="TypedText"/> generated at the specified visible character index.</returns>
    /// <param name="text">Text to parse.</param>
    /// <param name="visibleCharacterIndex">Visible character index (ignores tags).</param>
    public string GetTypedTextAt(string text, int visibleCharacterIndex)
    {
        var textAsSymbolList = CreateSymbolListFromText(text);

        // Split the text into shown and hide strings based on the actual visible characters
        int printedCharCount     = 0;
        var shownText            = string.Empty;
        var hiddenText           = string.Empty;
        var lastVisibleCharacter = char.MinValue;

        foreach (var symbol in textAsSymbolList)
        {
            if (printedCharCount <= visibleCharacterIndex)
            {
                shownText += symbol.Text;

                // Keep track of the visible characters that have been printed
                if (!symbol.IsTag)
                {
                    lastVisibleCharacter = symbol.Character.ToCharArray()[0];
                }
            }
            else
            {
                hiddenText += symbol.Text;
            }

            if (!symbol.IsTag)
            {
                printedCharCount++;
            }
        }

        var activeTags = GetActiveTagsInSymbolList(textAsSymbolList, visibleCharacterIndex);

        // Remove closing tags for active tags from hidden text (move to before color hide tag)
        foreach (var activeTag in activeTags)
        {
            hiddenText = RemoveFirstOccurance(hiddenText, activeTag.ClosingTagText);
        }

        // Remove all color tags from hidden text so that they don't cause it to be shown
        // ex: <color=clear>This should <color=red>be clear</color></color> will show 'be clear" in red
        hiddenText = RichTextTag.RemoveTagsFromString(hiddenText, "color");

        // Add the hidden text, provided there is text to hide
        if (!string.IsNullOrEmpty(hiddenText))
        {
            var hiddenTag = RichTextTag.ClearColorTag;
            hiddenText = hiddenText.Insert(0, hiddenTag.TagText);
            hiddenText = hiddenText.Insert(hiddenText.Length, hiddenTag.ClosingTagText);
        }

        // Add back in closing tags in reverse order
        for (int i = 0; i < activeTags.Count; ++i)
        {
            hiddenText = hiddenText.Insert(0, activeTags[i].ClosingTagText);
        }

        // Remove all custom tags since Unity will display them when printed (it doesn't recognize them as rich text tags)
        var printText = shownText + hiddenText;

        foreach (var customTag in CustomTagTypes)
        {
            printText = RichTextTag.RemoveTagsFromString(printText, customTag);
        }

        // Calculate Delay, if active
        var delay = 0.0f;

        foreach (var activeTag in activeTags)
        {
            if (activeTag.TagType == "delay")
            {
                try
                {
                    delay = activeTag.IsOpeningTag ? float.Parse(activeTag.Parameter) : 0.0f;
                }
                catch (System.FormatException e)
                {
                    var warning = string.Format(
                        "TypedTextGenerator found Invalid paramter format in tag [{0}]. " +
                        "Parameter [{1}] does not parse to a float. Exception: {2}",
                        activeTag,
                        activeTag.Parameter,
                        e);
                    Debug.Log(warning);
                    delay = 0.0f;
                }
            }
        }

        return(printText);
    }
Esempio n. 19
0
        public static List <VisualElement> AddRichText(string text, IButtonRegistry buttonRegistry, VisualElement root, bool isInsideCodeBlock)
        {
            List <VisualElement>   results   = new List <VisualElement>();
            IEnumerable <RichText> richTexts = ParseRichText(text, isInsideCodeBlock);
            //Parse rich texts to create paragraphs.
            List <List <RichText> > paragraphs = new List <List <RichText> > {
                new List <RichText>()
            };

            foreach (RichText richText in richTexts)
            {
                if (richText.richTextTag.tag == RichTextTag.Tag.button || richText.richTextTag.tag == RichTextTag.Tag.code)
                {
                    paragraphs[paragraphs.Count - 1].Add(richText);
                    continue;
                }

                string[] strings = richText.associatedText.Split('\n');
                for (int i = 0; i < strings.Length; i++)
                {
                    if (i != 0)
                    {
                        paragraphs.Add(new List <RichText>());
                    }
                    //Split paragraph content (already split by tag) into individual words
                    string[] wordSplit = Regex.Split(strings[i], @"(?<=[ -])");                     //Split but keep delimiters attached.
                    foreach (var word in wordSplit)
                    {
                        if (!string.IsNullOrEmpty(word))
                        {
                            paragraphs[paragraphs.Count - 1].Add(new RichText(richText.richTextTag, word));
                        }
                    }
                }
            }

            foreach (List <RichText> paragraph in paragraphs)
            {
                //Add all the paragraphs
                VisualElement rootTemp = root;
                root = AddParagraphContainer(root);
                for (int i = 0; i < paragraph.Count; i++)
                {
                    RichText word = paragraph[i];
                    if (i < paragraph.Count - 1)
                    {
                        //If there are more words
                        RichText nextWord = paragraph[i + 1];
                        string   nextText = nextWord.associatedText;
                        if (Regex.IsMatch(nextText, "^[^a-zA-Z] ?"))
                        {
                            VisualElement inlineGroup = new VisualElement();
                            root.Add(inlineGroup);
                            inlineGroup.AddToClassList("inline-text-group");
                            AddRichTextInternal(word, inlineGroup);
                            AddRichTextInternal(nextWord, inlineGroup);
                            ++i;
                            continue;
                        }
                    }

                    AddRichTextInternal(word, root);

                    //Add all the words and style them.
                    void AddRichTextInternal(RichText richText, VisualElement rootToAddTo)
                    {
                        RichTextTag tag        = richText.richTextTag;
                        TextElement inlineText = null;

                        switch (tag.tag)
                        {
                        case RichTextTag.Tag.none:
                            inlineText = AddInlineText(richText.associatedText, rootToAddTo);
                            break;

                        case RichTextTag.Tag.button:
                            if (buttonRegistry == null)
                            {
                                Debug.LogWarning("There was no ButtonRegistry provided to AddRichText. Button tags will not function.");
                                inlineText = AddInlineButton(() => Debug.LogWarning("There was no ButtonRegistry provided to AddRichText. Button tags will not function."), richText.associatedText, rootToAddTo);
                                break;
                            }
                            if (!buttonRegistry.GetRegisteredButtonAction(tag.stringVariables, out Action action))
                            {
                                return;
                            }
                            inlineText = AddInlineButton(action, richText.associatedText, rootToAddTo);
                            break;

                        case RichTextTag.Tag.code:
                            //Scroll
                            ScrollView    codeScroll       = new ScrollView(ScrollViewMode.Horizontal);
                            VisualElement contentContainer = codeScroll.contentContainer;
                            codeScroll.contentViewport.style.flexDirection = FlexDirection.Column;
                            codeScroll.contentViewport.style.alignItems    = Align.Stretch;
                            codeScroll.AddToClassList("code-scroll");
                            root.Add(codeScroll);

                            contentContainer.ClearClassList();
                            contentContainer.AddToClassList("code-container");
                            VisualElement codeContainer = contentContainer;

                            CSharpHighlighter highlighter = new CSharpHighlighter
                            {
                                AddStyleDefinition = false
                            };
                            // To add code, we first use the CSharpHighlighter to construct rich text for us.
                            string highlit = highlighter.Highlight(richText.associatedText);
                            // After constructing new rich text we pass the text back recursively through this function with the new parent.
                            AddRichText(highlit, buttonRegistry, codeContainer, true);                                     // only parse spans because this is all the CSharpHighlighter parses.
                            //Finalise content container
                            foreach (VisualElement child in codeContainer.Children())
                            {
                                if (child.ClassListContains(paragraphContainerClass))
                                {
                                    child.AddToClassList("code");
                                    if (child.childCount == 1)
                                    {
                                        AddInlineText("", child);                                                //This seems to be required to get layout to function properly.
                                    }
                                }
                            }

                            //Begin Hack
                            FieldInfo m_inheritedStyle = typeof(VisualElement).GetField("inheritedStyle", BindingFlags.NonPublic | BindingFlags.Instance);
                            if (m_inheritedStyle == null)
                            {
                                m_inheritedStyle = typeof(VisualElement).GetField("m_InheritedStylesData", BindingFlags.NonPublic | BindingFlags.Instance);
                            }
                            Type      inheritedStylesData = Type.GetType("UnityEngine.UIElements.StyleSheets.InheritedStylesData,UnityEngine");
                            FieldInfo font     = inheritedStylesData.GetField("font", BindingFlags.Public | BindingFlags.Instance);
                            FieldInfo fontSize = inheritedStylesData.GetField("fontSize", BindingFlags.Public | BindingFlags.Instance);
                            Font      consola  = (Font)EditorGUIUtility.Load("consola");

                            contentContainer.Query <Label>().ForEach(l =>
                            {
                                l.AddToClassList("code");


                                //Hack to regenerate the font size as Rich Text tags are removed from the original calculation.
                                object value      = m_inheritedStyle.GetValue(l);
                                StyleFont fontVar = (StyleFont)font.GetValue(value);
                                fontVar.value     = consola;
                                font.SetValue(value, fontVar);
                                StyleLength fontSizeVar = 12;                                        // = (StyleLength) fontSize.GetValue(value); //This doesn't seem to work properly, hard coded for now.
                                fontSize.SetValue(value, fontSizeVar);
                                m_inheritedStyle.SetValue(l, value);
                                Vector2 measuredTextSize = l.MeasureTextSize(l.text.Replace('>', ' '), 0, VisualElement.MeasureMode.Undefined, 0, VisualElement.MeasureMode.Undefined);
                                l.style.width            = measuredTextSize.x;
                                l.style.height           = measuredTextSize.y;
                            });

                            //Button
                            Button codeCopyButtonButtonContainer = new Button(() =>
                            {
                                EditorGUIUtility.systemCopyBuffer = richText.associatedText;
                                Debug.Log("Copied Code to Clipboard");
                            });
                            codeCopyButtonButtonContainer.ClearClassList();
                            codeCopyButtonButtonContainer.AddToClassList("code-button");
                            codeCopyButtonButtonContainer.StretchToParentSize();
                            codeContainer.Add(codeCopyButtonButtonContainer);

                            break;

                        case RichTextTag.Tag.span:
                            Label spanLabel = new Label
                            {
                                text = richText.associatedText
                            };
                            spanLabel.AddToClassList(tag.stringVariables);
                            rootToAddTo.Add(spanLabel);
                            break;

                        case RichTextTag.Tag.image:
                            throw new NotImplementedException();

                        default:
                            throw new ArgumentOutOfRangeException();
                        }

                        if (inlineText != null)
                        {
                            inlineText.style.unityFontStyleAndWeight = tag.fontStyle;
                            if (tag.size > 0)
                            {
                                inlineText.style.fontSize = tag.size;
                            }
                            if (tag.color != Color.clear)
                            {
                                inlineText.style.color = tag.color;
                            }
                            results.Add(inlineText);
                        }
                    }
                }

                root = rootTemp;
            }

            return(results);

            /*void RichTextDebug(string richText) => Debug.Log(GetRichTextCapableText(richText));
             * string GetRichTextCapableText(string richText) => text.Replace("<", "<<b></b>");*/
        }
Esempio n. 20
0
    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        if (font == null)
        {
            return;
        }

        // We don't care if we the font Texture changes while we are doing our Update.
        // The end result of cachedTextGenerator will be valid for this instance.
        // Otherwise we can get issues like Case 619238.
        m_DisableFontTextureRebuiltCallback = true;

        //处理事件
        eventList.Clear();

        //处理图片标签
        string           richText = text;
        IList <UIVertex> verts    = null;

        richText = CalculateLayoutWithImage(richText, out verts);

        //处理文字标签
        List <RichTextTag> tagList = null;

        richTextParser.Parse(richText, out tagList);
        for (int i = 0; i < tagList.Count; i++)
        {
            RichTextTag tag = tagList[i];
            switch (tag.tagType)
            {
            case RichTextTagType.None:
                break;

            case RichTextTagType.Underline:
                ApplyUnderlineEffect(tag as RichTextUnderlineTag, verts);
                break;

            default:
                break;
            }
        }

        Rect inputRect = rectTransform.rect;

        // get the text alignment anchor point for the text in local space
        Vector2 textAnchorPivot = GetTextAnchorPivot(fontData.alignment);
        Vector2 refPoint        = Vector2.zero;

        refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x);
        refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y);

        // Determine fraction of pixel to offset text mesh.
        Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;

        // Apply the offset to the vertices
        //IList<UIVertex> verts = cachedTextGenerator.verts;
        float unitsPerPixel = 1 / pixelsPerUnit;
        //Last 4 verts are always a new line...
        int vertCount = verts.Count - 4;

        toFill.Clear();
        if (roundingOffset != Vector2.zero)
        {
            for (int i = 0; i < vertCount; ++i)
            {
                int tempVertsIndex = i & 3;
                m_TempVerts[tempVertsIndex]             = verts[i];
                m_TempVerts[tempVertsIndex].position   *= unitsPerPixel;
                m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
                m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
                if (tempVertsIndex == 3)
                {
                    toFill.AddUIVertexQuad(m_TempVerts);
                }
            }
        }
        else
        {
            //Debug.Log(unitsPerPixel);
            for (int i = 0; i < vertCount; ++i)
            {
                int tempVertsIndex = i & 3;
                m_TempVerts[tempVertsIndex]           = verts[i];
                m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                if (tempVertsIndex == 3)
                {
                    toFill.AddUIVertexQuad(m_TempVerts);
                }
                //Debug.LogWarning(i + "_" + tempVertsIndex + "_" + m_TempVerts[tempVertsIndex].position);
            }
        }
        m_DisableFontTextureRebuiltCallback = false;
    }
Esempio n. 21
0
 public RichText(RichTextTag richTextTag, string associatedText)
 {
     this.richTextTag    = richTextTag;
     this.associatedText = associatedText;
 }