Hello! Recently I’ve been working on this little project of mine that allows for real time syntax highlighting in game! I think it’s real cool and would like to share it with all of you!
(I did this by overlaying a TextLabel with RichText enabled, on top of TextBox and having it update the TextLabel with what was in the TextBox)
I have also made this module open source! (feel free to use it in any of your projects!)
Below is the module’s source.
local highlighter = {}
local keywords = {
lua = {
"and", "break", "or", "else", "elseif", "if", "then", "until", "repeat", "while", "do", "for", "in", "end",
"local", "return", "function", "export"
},
rbx = {
"game", "workspace", "script", "math", "string", "table", "task", "wait", "select", "next", "Enum",
"error", "warn", "tick", "assert", "shared", "loadstring", "tonumber", "tostring", "type",
"typeof", "unpack", "print", "Instance", "CFrame", "Vector3", "Vector2", "Color3", "UDim", "UDim2", "Ray", "BrickColor",
"OverlapParams", "RaycastParams", "Axes", "Random", "Region3", "Rect", "TweenInfo",
"collectgarbage", "not", "utf8", "pcall", "xpcall", "_G", "setmetatable", "getmetatable", "os", "pairs", "ipairs"
},
operators = {
"#", "+", "-", "*", "%", "/", "^", "=", "~", "=", "<", ">", ",", ".", "(", ")", "{", "}", "[", "]", ";", ":"
}
}
local colors = {
numbers = Color3.fromRGB(255, 198, 0),
boolean = Color3.fromRGB(214, 128, 23),
operator = Color3.fromRGB(232, 210, 40),
lua = Color3.fromRGB(160, 87, 248),
rbx = Color3.fromRGB(146, 180, 253),
str = Color3.fromRGB(56, 241, 87),
comment = Color3.fromRGB(103, 110, 149),
null = Color3.fromRGB(79, 79, 79),
call = Color3.fromRGB(130, 170, 255),
self_call = Color3.fromRGB(227, 201, 141),
local_color = Color3.fromRGB(199, 146, 234),
function_color = Color3.fromRGB(241, 122, 124),
self_color = Color3.fromRGB(146, 134, 234),
local_property = Color3.fromRGB(129, 222, 255),
}
local function createKeywordSet(keywords)
local keywordSet = {}
for _, keyword in ipairs(keywords) do
keywordSet[keyword] = true
end
return keywordSet
end
local luaSet = createKeywordSet(keywords.lua)
local rbxSet = createKeywordSet(keywords.rbx)
local operatorsSet = createKeywordSet(keywords.operators)
local function getHighlight(tokens, index)
local token = tokens[index]
if colors[token .. "_color"] then
return colors[token .. "_color"]
end
if tonumber(token) then
return colors.numbers
elseif token == "nil" then
return colors.null
elseif token:sub(1, 2) == "--" then
return colors.comment
elseif operatorsSet[token] then
return colors.operator
elseif luaSet[token] then
return colors.rbx
elseif rbxSet[token] then
return colors.lua
elseif token:sub(1, 1) == "\"" or token:sub(1, 1) == "\'" then
return colors.str
elseif token == "true" or token == "false" then
return colors.boolean
end
if tokens[index + 1] == "(" then
if tokens[index - 1] == ":" then
return colors.self_call
end
return colors.call
end
if tokens[index - 1] == "." then
if tokens[index - 2] == "Enum" then
return colors.rbx
end
return colors.local_property
end
end
function highlighter.run(source)
local tokens = {}
local currentToken = ""
local inString = false
local inComment = false
local commentPersist = false
for i = 1, #source do
local character = source:sub(i, i)
if inComment then
if character == "\n" and not commentPersist then
table.insert(tokens, currentToken)
table.insert(tokens, character)
currentToken = ""
inComment = false
elseif source:sub(i - 1, i) == "]]" and commentPersist then
currentToken ..= "]"
table.insert(tokens, currentToken)
currentToken = ""
inComment = false
commentPersist = false
else
currentToken = currentToken .. character
end
elseif inString then
if character == inString and source:sub(i-1, i-1) ~= "\\" or character == "\n" then
currentToken = currentToken .. character
inString = false
else
currentToken = currentToken .. character
end
else
if source:sub(i, i + 1) == "--" then
table.insert(tokens, currentToken)
currentToken = "-"
inComment = true
commentPersist = source:sub(i + 2, i + 3) == "[["
elseif character == "\"" or character == "\'" then
table.insert(tokens, currentToken)
currentToken = character
inString = character
elseif operatorsSet[character] then
table.insert(tokens, currentToken)
table.insert(tokens, character)
currentToken = ""
elseif character:match("[%w_]") then
currentToken = currentToken .. character
else
table.insert(tokens, currentToken)
table.insert(tokens, character)
currentToken = ""
end
end
end
table.insert(tokens, currentToken)
local highlighted = {}
for i, token in ipairs(tokens) do
local highlight = getHighlight(tokens, i)
if highlight then
local syntax = string.format("<font color = \"#%s\">%s</font>", highlight:ToHex(), token:gsub("<", "<"):gsub(">", ">"))
table.insert(highlighted, syntax)
else
table.insert(highlighted, token)
end
end
return table.concat(highlighted)
end
return highlighter
I am hoping to one day improve this to have autocompleting and alike, but I don’t think I could tackle something that challenging and complex (idk it might be real simple and I just don’t know it).
Thank you for reading and have a wonderful day!