Auto-set a color to a word on a TextArea

I know hot to set a color in a TextArea.

Imagine if I want to set all occurences of the “Error” word in a TextArea to Red and do nothing if this word do not appear in this text.

I had this idea some days ago, and, day after day, I do not have any idea to where/how I can start.

“Allow Styled Text” is by default on. you have to select the text range and then you can set the color.
TextArea1.SelectionStart = 0
TextArea1.SelectionLength = 10
TextArea1.SelectionTextColor = Color.Red

https://documentation.xojo.com/api/data_types/string.html#string-indexof

or you have to use
https://documentation.xojo.com/api/text/styledtext.html

And to add: You can use the RegEx class (https://documentation.xojo.com/api/text/regular_expressions/regex.html) to find the SelectionStart/SelectionLength values. You just need to find the proper event to put the highlight update code into. For small text areas, TextChange would probably work. If you have a bunch of text, you may need to work on making it more efficient.

Thank you for your advices.

Do you really think Xojo IDE (the Code Editor) do it that way ?

I do not, and this is why I asked here.

I don’t think they are using a TextArea…

-Karen

You’re right. It has been said several times this is a canvas subclass (it was so in the past, but I don’t expect this has changed since).

Anyway, when I enter two consecutive spaces, the IDE turns that into “. ” like a TextArea controlled by the OS would. I can’t see why Xojo would have added the same foolish behaviour if they can control the editor as they want… :thinking:

Yes, the OS knows better than me what want to write too.

Fortunately, Xojo flag that at run time, s I can remove them / change the OS setting.

And, for you, a TextArea is created with what ?

In a Graphic computer, everything is draw on screen …

a Code Editor is very difficult to create because of special features.
i created a ide for blitz basic long ago.
i guess xojo using a open source editor component.

sure it must analyze the text and then it can choose a color/style for each word.
it have a state machine for the syntax highlighting.
this one is a remark
REM if ... then
this one is a condition
if ... then

method that can be called at textchange event

Public Sub ReColor(t As TextArea)
  Var ms As Integer = t.SelectionStart
  Var ml As Integer = t.SelectionLength
  
  t.SelectionStart = 0
  t.SelectionLength = t.Text.Length
  t.SelectionTextColor = Color.Black
  
  Var s As String = t.Text
  Var l As Integer = s.Length-1
  
  Var index2 As Integer
  Var word As String = "error"
  For index1 As Integer = 0 To l
    index2 = s.IndexOf(index1, word)
    If index2 = index1 Then
      t.SelectionStart = index1
      t.SelectionLength = word.Length
      t.SelectionTextColor = Color.Red
    End If
  Next
  
  t.SelectionStart = ms
  t.SelectionLength = ml
End Sub

Thank you Markus for the Code. I like it.

I may be wrong, but what about “flashing” ? I mean… selecting words to colorize them takes time, is the process visible ?

I have to get a better eye (read carefully) the StyleRun entries n the LR. As is, I do not know if I can read () the text from there, or f I have to read () the text from TextArea1.Text.

(*) scan the text seeking the word(s) I want (then get the position, change the color with a StyleRun…)

I have many things to do today, so I have to postpone this until tomorrow.

i just saw there is a method to colorize parts of the text.
TextArea1.StyledText.TextColor(7, 5) = &cff0000 // "World" is now red

The TextArea is using an OS based Control With the the Xojo X-Platform API on top of that…

Although the textArea provides a lot of functionality, you don’t have control over all the details of text rendering… that means you also have limitations using the control that don’t exist when you do all the drawing yourself.

That is why the code editor does not use a TextArea.

-Karen

That use a GrafPort…

Good question:

how do you know the correct values are 7,5 ?

When I implemented keyword highlighting for a TextArea once I wrote a scanner which produced an Array of Pairs with start positions and word lengths (quite fast) and then I looped the resulting array and applied (pseudo code):

TextArea.StyledText.TextColor(Tokens(i).Left, Tokens(i).Right) = Color

The coloring itself was a lot slower than my scanner, but that seems to be a Xojo issue and I couldn’t get it any faster. At least using TextArea.StyledText was much faster than selecting text in the TextArea, which was painfully slow with larger texts.

1 Like

That was my feeling.

Thank you Jens.

Conclusion:
a. Scan the text,

  • store the word(s) Start, Len and Color (to use for this word)
    b. Apply the color using the above data once the text scan is over using StyleRun.

I only have to implement that.

I went for a RegEx-based solution when facing the same problem. It works sufficiently fast for relatively short texts. I use TextArea.StyledText and call the syntax highlighting stuff for the current paragraph when the text changes. The action part of a timer syntax highlights the whole text periodically.

The core is basically an array of RegEx patterns which I loop through to find matches. I then colorize the matches.

1 Like

Scanning out of the back of my head with room for improvement (method in a Module):

Public Sub Highlight(Extends TA As TextArea, SearchString As String)
  #Pragma DisableBackgroundTasks
  
  Var Tokens() As Pair
  
  Var s As String = SearchString.Lowercase
  Var lng As Integer = s.Length
  Var tmp() As String = TA.Text.Lowercase.ReplaceAll(EndOfLine, " ").Split(" ")
  Var lim As Integer = tmp.LastIndex
  Var cnt As Integer = 1
  
  For i As Integer = 0 To lim
    If tmp(i) = s Then
      Tokens.Add(New Pair(cnt, lng))
    End If
    
    cnt = cnt + tmp(i).Length
    If i > 0 Then
      cnt = cnt + 1
    End If
  Next
  
  Colorize(TA.StyledText, Tokens)
End Sub

It may look a bit clumsy, but in my use case it worked faster than RegEx.
And the Colorize method:

Public Sub Colorize(ST As StyledText, Tokens() As Pair)
  #Pragma DisableBackgroundTasks
  
  Var lim As Integer = Tokens.LastRowIndex
  
  For i As Integer = 0 To lim
    ST.TextColor(Tokens(i).Left, Tokens(i).Right) = &c006699
  Next
End Sub

I just tried it with a text of 5000 words with about 320 resulting tokens of my search string. In debug mode it took the scanner <10 ms to tokenize the whole text, but the colorize method took almost 700 ms (which is strange because in an older project it also takes a bit to colorize – about 4 times more than scanning – but not THAT long). I wish there was a much more performant way of highlighting a text in a TextArea …

You could make this process more efficient if you could tell what part of the TextArea changed during the TextUpdate. Then you would only need to Search/Highlight around the changed area.

Set the TextArea (or Window) Invisible, then scan/colorize, and then set it back to visible…

There are several ways to improve performance of colorizing (the above was just supposed to be a hint of direction), but still I have never come even close to scanning speed. There seem to be some performance limits with StyledText I couldn’t work around.