Conflicting HTML tags for executor plugin

Hello!

I’m making a code executor plugin, and I’m currently making the player’s input text different colours based on different keywords. I’m using RichText and HTML tags to colour different keywords, but there’s a small issue when I try and colour strings and numbers green, it detects the font HTML tag and causes it to look all horrible because it replaces the HTML markup as well.

Here’s the script:

local function removeHTMLTags(str: string): string
	return str:gsub("<[^>]+>", "")
end

codeBox.Focused:Connect(function()
	local text = codeBox.Text
	local cleanedText = removeHTMLTags(text)
	codeBox.Text = cleanedText
end)

codeBox.FocusLost:Connect(function(_enter: boolean, _input: InputObject)
	--adding RichText colours for the keywords
	local newText = codeBox.Text

	--remove
	newText = removeHTMLTags(newText)

	--make strings green
	newText = string.gsub(newText, "\"(.-)\"", '<font color="rgb(85, 170, 0)">"%1"</font>')
	
	--make numbers green
	newText = string.gsub(newText, "\"(%d+)\"", '<font color="rgb(85, 170, 0)">"%1"</font>')

	--colour function names and keywords
	newText = string.gsub(newText, "([%a_][%w_]*)", function(word: string): string
		if keywords[word] then
			return string.format('<font color="%s">%s</font>', keywords[word], word)
		elseif globals[word] then
			return string.format('<font color="%s">%s</font>', globalsColour, word)
		else
			return string.format('<font color="%s">%s</font>', functionColour, word)
		end
	end)

	--re-add stroke and re-assign text
	codeBox.Text = string.format('<stroke color="rgb(0, 0, 0)" thickness="2">%s</stroke>', newText)
end)

I’ve tried changing the order of the substitutions, but there’s nothing I have found to be able to fix this other than completely removing the number and string colouring.

Any help is appreciated.

Use the property ContentText of text labels that ignores rich text tags:

print(codeBox.Text) --should print text & rich text tags
print(codeBox.ContentText) --should print the visible text only

That helps, but I’m having trouble applying it because only the last part (which colours the keywords) will apply. Do you know how I could make each step apply? If I read the ContextText property, it gets rid of previous HTML tags.

New code:

codeBox.FocusLost:Connect(function(_enter: boolean, _input: InputObject)
	--adding RichText colours for the keywords
	local newText = codeBox.ContentText

	--make strings green
	codeBox.Text = string.gsub(newText, "\"(.-)\"", '<font color="rgb(85, 170, 0)">"%1"</font>')
	
	--make numbers green
	codeBox.Text = string.gsub(codeBox.ContentText, "\"(%d+)\"", '<font color="rgb(85, 170, 0)">"%1"</font>')
	
	newText = codeBox.Text
	
	--colour keywords
	codeBox.Text = string.gsub(newText, "([%a_][%w_]*)", function(word)
		if keywords[word] then
			return string.format('<font color="%s">%s</font>', keywords[word], word)
		elseif table.find(globals, word) then
			return string.format('<font color="%s">%s</font>', globalsColour, word)
		else
			return word --leave other identifiers unchanged
		end
	end)

	--re-add stroke and re-assign text
	codeBox.Text = `<stroke color="rgb(0, 0, 0)" thickness="2">{codeBox.Text}</stroke>`
end)

You can use it for specific segments of text:

local function removeRichtext(s: string): string
	local label = Instance.new("TextLabel")
	label.RichText = true 
	label.Text = s
	return label.ContentText
end

--should print "foo bar"
print(removeRichtext("<font color=\"rgb(85, 170, 0)\">foo bar</font>"))

Yes, that helps to remove the HTML tags on TextBox.Focused event, but it doesn’t help with the conflicting HTML tags issue I am currently having. If I apply it to one segment of code, I lose the HTML tags from that segment. My issue is that the string.gsub function detects the HTML tags when substituting, but if I use ContextText for that, the other HTML tags are lost.