I need to highlight user input code. I tried using rich text, but when you try to modify the text you modify color tags too. So is there a way to change the color of word without tags, or a way to ignore them?
You’d have to write your own parser. TextMeshPro is a free asset, and will soon be integrated into Unity’s engine. For now, you can download the asset and add it to your project.
You could try that and / or give a little more detail on what you’re looking for/situation.
Ok, thanks, TextMeshPro is realy good, but it seems to do strange thing to caret position: after inserting color tags it put caret at the begining of a word, and after that you cant put any character until you move caret by arrow keys. I tried to store caret position before inserting and restore after, it fixed unability to put characters, but the caret still is before the word, any idea why?
public void BeautifyText()
{
string toB = text.GetComponent<TMP_InputField>().text;
int pos = text.GetComponent<TMP_InputField>().caretPosition;
toB = System.Text.RegularExpressions.Regex.Replace(toB, "<[^>]*>", "", RegexOptions.Singleline);
toB = System.Text.RegularExpressions.Regex.Replace(toB, "for", "<color=#0000ffff>for</color>", RegexOptions.Singleline);
text.GetComponent<TMP_InputField>().text = toB;
text.GetComponent<TMP_InputField>().caretPosition = pos;
}
I’m not sure if that is the most efficient means, if you are checking the entire text after every entry/character, … but that is sort of another story.
As for the caret position, I guess it’s because of how you change it in there that its position isn’t updated.
Right now, you’re storing the caret position before the update, but you do not increment it if the text is found/altered. Right?
This just for test i will alter it later.
Yeah, but i checked the caret positions after word with and without insertion of tags - its the same. And i already tried increment the position and it does basicly doesnt work cause even if i add number of characters in tag + in word (actualy no matter how many i add) caret still appear at the beggining of the word.
This is what I did to get it working:
This is in the function you posted (or part of it, not replacing it)
string s = "<color=#0000ffff>for</color>";
int len = s.Length;
GetComponent<TMP_InputField>().text = toB;
StartCoroutine(moveCaret(pos + len));
}
IEnumerator moveCaret(int pos)
{
yield return new WaitForEndOfFrame();
GetComponent<TMP_InputField>().caretPosition = pos;
}
It’s snipped to the relevant bits
lol then there is this even easier method
just add : GetComponent<TMP_InputField>().MoveTextEnd(false);
after you set the .text portion.
Remove the coroutine
And one last follow up.: my 2 above examples work in their own right, but when I tried to uncheck “allow rich text editing” (so users wouldn’t see the color codes when backspacing, for example), then it wouldn’t advance all the way to the end.
I tried a few things, and what worked was firing the coroutine (which didn’t need an int parameter anymore), yielding until the end of the frame, and then calling the method " MoveTextEnd(false)" and that worked every time in my tests.
Yeah, it works, but there is slight problem - you cant modify the code after you write it cause it always jumps at the end of string.
Ya, I can imagine that… um… from where (/when) are you calling your method to adjust the text? After each character is inputted? Is there in-place editing (ie: can they skip backwords by clicking?) Gets more complicated, depending on the situation…
I call it every time enter or space pressed (actually i dont think it matter)
Sorry english isn’t my native language, i did not understand the question.
Actually highlighting with tags is pretty complicated, is there another methods, something like shaders or something?
Yes, sorry , it is a bit complicated. I do not know of any other means. Maybe someone else does.
TextMeshPro does have word counting, though I’ve only looked at it briefly. If you could utilize that, you might be able to adjust your function to look at only the most recent word, and if it matches a word you want to highlight, then you change it , otherwise you don’t. This way you are only working on 1 word at a time, instead of parsing the entire entry. It would also mean that you would have finer control over the caret’s position at any given time/update.
Just chiming in…
The Input Field has both caretPosition and stringPosition as well as selectionAnchorPosition and selectionStringAnchorPosition. The stringPosition takes into consideration the hidden rich text tags while the caretPosition only the visible text.
If you are inserting new text (tags) the caret position should not change while the stringPosition would most certainly need to be set correctly.
I have not tried changing / inserting new text in the Input Field manually but this should work. Hopefully with this additional information you’ll be able to make this work.
As suggested, you can also get information from textInfo.wordInfo[ ] which once the text has been processed / rendered will contain the updated information for each word. When inserting text via scripting, you might need to use .ForceMeshUpdate() to force the textInfo and text data to be updated.
Oh, nice. That’s a nice bit of added information, that I will hopefully remember in the future
Can anyone share the finished code?
If anyone else finds this, I found a solution that might work (The loop is not needed but my project required looping through a list of words)
Also the numbers being added on lines 18 and 22 come from the number of characters in the strings used to highlight the text, which includes the color (“<color=red>” and “”)
//Get Caret Position Before Replacement
int CurrentCaretPos = CurrentAnswerField.stringPosition;
//Get The Number of Previously Replaced Items
int ColoredIndexes = Regex.Matches(CurrentAnswerField.text, "<color=red>").Count;
//Reset Red Words
CurrentAnswerField.text = CurrentAnswerField.text.Replace("<color=red>", "");
CurrentAnswerField.text = CurrentAnswerField.text.Replace("</color>", "");
//Replace Words
foreach (ThesaurusWords Current in ThesaurusWords_List)
{
CurrentAnswerField.text = Regex.Replace(CurrentAnswerField.text, Current.Word, "<color=red>" + Current.Word + "</color>", RegexOptions.IgnoreCase);
int HighlightDiff = (Regex.Matches(CurrentAnswerField.text, "<color=red>").Count - ColoredIndexes);
if (HighlightDiff > 0)
{
CurrentCaretPos += (19 * HighlightDiff);
}
else
{
CurrentCaretPos += (11 * HighlightDiff);
}
}
//Reset Cursor Position
CurrentAnswerField.caretPosition = CurrentCaretPos;
CurrentAnswerField.stringPosition = CurrentCaretPos;