-- For All Indents And Purposes local revision = 17 -- Original author: kristofer.karlsson@gmail.com -- IUP adaptation: pixel@grumpycoder.net -- For All Indents And Purposes - -- a indentation + syntax highlighting library -- All valid lua code should be processed correctly. -- Usage -------- -- hook the textboxes that you want to have indentation like this: -- IndentationLib.enable(editbox [, colorTable [, tabWidth] ]) -- if you don't select a color table, it will use the default. -- Read through this code for further usage help. -- (The documentation IS the code) if not IndentationLib then IndentationLib = {} end if not IndentationLib.revision or revision > IndentationLib.revision then local lib = IndentationLib lib.revision = revision local stringlen = string.len local stringformat = string.format local stringfind = string.find local stringsub = string.sub local stringbyte = string.byte local stringchar = string.char local stringrep = string.rep local stringgsub = string.gsub local workingTable = {} local workingTable2 = {} local function tableclear(t) for k in next,t do t[k] = nil end end local function stringinsert(s, pos, insertStr) return stringsub(s, 1, pos) .. insertStr .. stringsub(s, pos + 1) end lib.stringinsert = stringinsert local function stringdelete(s, pos1, pos2) return stringsub(s, 1, pos1 - 1) .. stringsub(s, pos2 + 1) end lib.stringdelete = stringdelete -- token types local tokens = {} lib.tokens = tokens tokens.TOKEN_UNKNOWN = 0 tokens.TOKEN_NUMBER = 1 tokens.TOKEN_LINEBREAK = 2 tokens.TOKEN_WHITESPACE = 3 tokens.TOKEN_IDENTIFIER = 4 tokens.TOKEN_ASSIGNMENT = 5 tokens.TOKEN_EQUALITY = 6 tokens.TOKEN_MINUS = 7 tokens.TOKEN_COMMENT_SHORT = 8 tokens.TOKEN_COMMENT_LONG = 9 tokens.TOKEN_STRING = 10 tokens.TOKEN_LEFTBRACKET = 11 tokens.TOKEN_PERIOD = 12 tokens.TOKEN_DOUBLEPERIOD = 13 tokens.TOKEN_TRIPLEPERIOD = 14 tokens.TOKEN_LTE = 15 tokens.TOKEN_LT = 16 tokens.TOKEN_GTE = 17 tokens.TOKEN_GT = 18 tokens.TOKEN_NOTEQUAL = 19 tokens.TOKEN_COMMA = 20 tokens.TOKEN_SEMICOLON = 21 tokens.TOKEN_COLON = 22 tokens.TOKEN_LEFTPAREN = 23 tokens.TOKEN_RIGHTPAREN = 24 tokens.TOKEN_PLUS = 25 tokens.TOKEN_SLASH = 27 tokens.TOKEN_LEFTWING = 28 tokens.TOKEN_RIGHTWING = 29 tokens.TOKEN_CIRCUMFLEX = 30 tokens.TOKEN_ASTERISK = 31 tokens.TOKEN_RIGHTBRACKET = 32 tokens.TOKEN_KEYWORD = 33 tokens.TOKEN_SPECIAL = 34 tokens.TOKEN_VERTICAL = 35 tokens.TOKEN_TILDE = 36 tokens.TOKEN_HASH = 39 tokens.TOKEN_PERCENT = 40 -- ascii codes local bytes = {} lib.bytes = bytes bytes.BYTE_LINEBREAK_UNIX = stringbyte("\n") bytes.BYTE_LINEBREAK_MAC = stringbyte("\r") bytes.BYTE_SINGLE_QUOTE = stringbyte("'") bytes.BYTE_DOUBLE_QUOTE = stringbyte('"') bytes.BYTE_0 = stringbyte("0") bytes.BYTE_9 = stringbyte("9") bytes.BYTE_PERIOD = stringbyte(".") bytes.BYTE_SPACE = stringbyte(" ") bytes.BYTE_TAB = stringbyte("\t") bytes.BYTE_E = stringbyte("E") bytes.BYTE_e = stringbyte("e") bytes.BYTE_MINUS = stringbyte("-") bytes.BYTE_EQUALS = stringbyte("=") bytes.BYTE_LEFTBRACKET = stringbyte("[") bytes.BYTE_RIGHTBRACKET = stringbyte("]") bytes.BYTE_BACKSLASH = stringbyte("\\") bytes.BYTE_COMMA = stringbyte(",") bytes.BYTE_SEMICOLON = stringbyte(";") bytes.BYTE_COLON = stringbyte(":") bytes.BYTE_LEFTPAREN = stringbyte("(") bytes.BYTE_RIGHTPAREN = stringbyte(")") bytes.BYTE_TILDE = stringbyte("~") bytes.BYTE_PLUS = stringbyte("+") bytes.BYTE_SLASH = stringbyte("/") bytes.BYTE_LEFTWING = stringbyte("{") bytes.BYTE_RIGHTWING = stringbyte("}") bytes.BYTE_CIRCUMFLEX = stringbyte("^") bytes.BYTE_ASTERISK = stringbyte("*") bytes.BYTE_LESSTHAN = stringbyte("<") bytes.BYTE_GREATERTHAN = stringbyte(">") bytes.BYTE_HASH = stringbyte("#") bytes.BYTE_PERCENT = stringbyte("%") local linebreakCharacters = {} lib.linebreakCharacters = linebreakCharacters linebreakCharacters[bytes.BYTE_LINEBREAK_UNIX] = 1 linebreakCharacters[bytes.BYTE_LINEBREAK_MAC] = 1 local whitespaceCharacters = {} lib.whitespaceCharacters = whitespaceCharacters whitespaceCharacters[bytes.BYTE_SPACE] = 1 whitespaceCharacters[bytes.BYTE_TAB] = 1 local specialCharacters = {} lib.specialCharacters = specialCharacters specialCharacters[bytes.BYTE_PERIOD] = -1 specialCharacters[bytes.BYTE_LESSTHAN] = -1 specialCharacters[bytes.BYTE_GREATERTHAN] = -1 specialCharacters[bytes.BYTE_LEFTBRACKET] = -1 specialCharacters[bytes.BYTE_EQUALS] = -1 specialCharacters[bytes.BYTE_MINUS] = -1 specialCharacters[bytes.BYTE_SINGLE_QUOTE] = -1 specialCharacters[bytes.BYTE_DOUBLE_QUOTE] = -1 specialCharacters[bytes.BYTE_TILDE] = -1 specialCharacters[bytes.BYTE_RIGHTBRACKET] = tokens.TOKEN_RIGHTBRACKET specialCharacters[bytes.BYTE_COMMA] = tokens.TOKEN_COMMA specialCharacters[bytes.BYTE_COLON] = tokens.TOKEN_COLON specialCharacters[bytes.BYTE_SEMICOLON] = tokens.TOKEN_SEMICOLON specialCharacters[bytes.BYTE_LEFTPAREN] = tokens.TOKEN_LEFTPAREN specialCharacters[bytes.BYTE_RIGHTPAREN] = tokens.TOKEN_RIGHTPAREN specialCharacters[bytes.BYTE_PLUS] = tokens.TOKEN_PLUS specialCharacters[bytes.BYTE_SLASH] = tokens.TOKEN_SLASH specialCharacters[bytes.BYTE_LEFTWING] = tokens.TOKEN_LEFTWING specialCharacters[bytes.BYTE_RIGHTWING] = tokens.TOKEN_RIGHTWING specialCharacters[bytes.BYTE_CIRCUMFLEX] = tokens.TOKEN_CIRCUMFLEX specialCharacters[bytes.BYTE_ASTERISK] = tokens.TOKEN_ASTERISK specialCharacters[bytes.BYTE_HASH] = tokens.TOKEN_HASH specialCharacters[bytes.BYTE_PERCENT] = tokens.TOKEN_PERCENT local function nextNumberExponentPartInt(text, pos) while true do local byte = stringbyte(text, pos) if not byte then return tokens.TOKEN_NUMBER, pos end if byte >= bytes.BYTE_0 and byte <= bytes.BYTE_9 then pos = pos + 1 else return tokens.TOKEN_NUMBER, pos end end end local function nextNumberExponentPart(text, pos) local byte = stringbyte(text, pos) if not byte then return tokens.TOKEN_NUMBER, pos end if byte == bytes.BYTE_MINUS then -- handle this case: a = 1.2e-- some comment -- i decide to let 1.2e be parsed as a a number byte = stringbyte(text, pos + 1) if byte == bytes.BYTE_MINUS then return tokens.TOKEN_NUMBER, pos end return nextNumberExponentPartInt(text, pos + 1) end return nextNumberExponentPartInt(text, pos) end local function nextNumberFractionPart(text, pos) while true do local byte = stringbyte(text, pos) if not byte then return tokens.TOKEN_NUMBER, pos end if byte >= bytes.BYTE_0 and byte <= bytes.BYTE_9 then pos = pos + 1 elseif byte == bytes.BYTE_E or byte == bytes.BYTE_e then return nextNumberExponentPart(text, pos + 1) else return tokens.TOKEN_NUMBER, pos end end end local function nextNumberIntPart(text, pos) while true do local byte = stringbyte(text, pos) if not byte then return tokens.TOKEN_NUMBER, pos end if byte >= bytes.BYTE_0 and byte <= bytes.BYTE_9 then pos = pos + 1 elseif byte == bytes.BYTE_PERIOD then return nextNumberFractionPart(text, pos + 1) elseif byte == bytes.BYTE_E or byte == bytes.BYTE_e then return nextNumberExponentPart(text, pos + 1) else return tokens.TOKEN_NUMBER, pos end end end local function nextIdentifier(text, pos) while true do local byte = stringbyte(text, pos) if not byte or linebreakCharacters[byte] or whitespaceCharacters[byte] or specialCharacters[byte] then return tokens.TOKEN_IDENTIFIER, pos end pos = pos + 1 end end -- returns false or: true, nextPos, equalsCount local function isBracketStringNext(text, pos) local byte = stringbyte(text, pos) if byte == bytes.BYTE_LEFTBRACKET then local pos2 = pos + 1 byte = stringbyte(text, pos2) while byte == bytes.BYTE_EQUALS do pos2 = pos2 + 1 byte = stringbyte(text, pos2) end if byte == bytes.BYTE_LEFTBRACKET then return true, pos2 + 1, (pos2 - 1) - pos else return false end else return false end end -- Already parsed the [==[ part when get here local function nextBracketString(text, pos, equalsCount) local state = 0 while true do local byte = stringbyte(text, pos) if not byte then return tokens.TOKEN_STRING, pos end if byte == bytes.BYTE_RIGHTBRACKET then if state == 0 then state = 1 elseif state == equalsCount + 1 then return tokens.TOKEN_STRING, pos + 1 else state = 0 end elseif byte == bytes.BYTE_EQUALS then if state > 0 then state = state + 1 end else state = 0 end pos = pos + 1 end end local function nextComment(text, pos) -- When we get here we have already parsed the "--" -- Check for long comment local isBracketString, nextPos, equalsCount = isBracketStringNext(text, pos) if isBracketString then local tokenType, nextPos2 = nextBracketString(text, nextPos, equalsCount) return tokens.TOKEN_COMMENT_LONG, nextPos2 end local byte = stringbyte(text, pos) -- Short comment, find the first linebreak while true do byte = stringbyte(text, pos) if not byte then return tokens.TOKEN_COMMENT_SHORT, pos end if linebreakCharacters[byte] then return tokens.TOKEN_COMMENT_SHORT, pos end pos = pos + 1 end end local function nextString(text, pos, character) local even = true while true do local byte = stringbyte(text, pos) if not byte then return tokens.TOKEN_STRING, pos end if byte == character then if even then return tokens.TOKEN_STRING, pos + 1 end end if byte == bytes.BYTE_BACKSLASH then even = not even else even = true end pos = pos + 1 end end -- INPUT -- 1: text: text to search in -- 2: tokenPos: where to start searching -- OUTPUT -- 1: token type -- 2: position after the last character of the token function nextToken(text, pos) local byte = stringbyte(text, pos) if not byte then return nil end if linebreakCharacters[byte] then return tokens.TOKEN_LINEBREAK, pos + 1 end if whitespaceCharacters[byte] then while true do pos = pos + 1 byte = stringbyte(text, pos) if not byte or not whitespaceCharacters[byte] then return tokens.TOKEN_WHITESPACE, pos end end end local token = specialCharacters[byte] if token then if token ~= -1 then return token, pos + 1 end if byte == bytes.BYTE_MINUS then byte = stringbyte(text, pos + 1) if byte == bytes.BYTE_MINUS then return nextComment(text, pos + 2) end return tokens.TOKEN_MINUS, pos + 1 end if byte == bytes.BYTE_SINGLE_QUOTE then return nextString(text, pos + 1, bytes.BYTE_SINGLE_QUOTE) end if byte == bytes.BYTE_DOUBLE_QUOTE then return nextString(text, pos + 1, bytes.BYTE_DOUBLE_QUOTE) end if byte == bytes.BYTE_LEFTBRACKET then local isBracketString, nextPos, equalsCount = isBracketStringNext(text, pos) if isBracketString then return nextBracketString(text, nextPos, equalsCount) else return tokens.TOKEN_LEFTBRACKET, pos + 1 end end if byte == bytes.BYTE_EQUALS then byte = stringbyte(text, pos + 1) if not byte then return tokens.TOKEN_ASSIGNMENT, pos + 1 end if byte == bytes.BYTE_EQUALS then return tokens.TOKEN_EQUALITY, pos + 2 end return tokens.TOKEN_ASSIGNMENT, pos + 1 end if byte == bytes.BYTE_PERIOD then byte = stringbyte(text, pos + 1) if not byte then return tokens.TOKEN_PERIOD, pos + 1 end if byte == bytes.BYTE_PERIOD then byte = stringbyte(text, pos + 2) if byte == bytes.BYTE_PERIOD then return tokens.TOKEN_TRIPLEPERIOD, pos + 3 end return tokens.TOKEN_DOUBLEPERIOD, pos + 2 elseif byte >= bytes.BYTE_0 and byte <= bytes.BYTE_9 then return nextNumberFractionPart(text, pos + 2) end return tokens.TOKEN_PERIOD, pos + 1 end if byte == bytes.BYTE_LESSTHAN then byte = stringbyte(text, pos + 1) if byte == bytes.BYTE_EQUALS then return tokens.TOKEN_LTE, pos + 2 end return tokens.TOKEN_LT, pos + 1 end if byte == bytes.BYTE_GREATERTHAN then byte = stringbyte(text, pos + 1) if byte == bytes.BYTE_EQUALS then return tokens.TOKEN_GTE, pos + 2 end return tokens.TOKEN_GT, pos + 1 end if byte == bytes.BYTE_TILDE then byte = stringbyte(text, pos + 1) if byte == bytes.BYTE_EQUALS then return tokens.TOKEN_NOTEQUAL, pos + 2 end return tokens.TOKEN_TILDE, pos + 1 end return tokens.TOKEN_UNKNOWN, pos + 1 elseif byte >= bytes.BYTE_0 and byte <= bytes.BYTE_9 then return nextNumberIntPart(text, pos + 1) else return nextIdentifier(text, pos + 1) end end -- Cool stuff begins here! (indentation and highlighting) local noIndentEffect = {0, 0} local indentLeft = {-1, 0} local indentRight = {0, 1} local indentBoth = {-1, 1} local keywords = {} lib.keywords = keywords keywords["and"] = noIndentEffect keywords["break"] = noIndentEffect keywords["false"] = noIndentEffect keywords["for"] = noIndentEffect keywords["if"] = noIndentEffect keywords["in"] = noIndentEffect keywords["local"] = noIndentEffect keywords["nil"] = noIndentEffect keywords["not"] = noIndentEffect keywords["or"] = noIndentEffect keywords["return"] = noIndentEffect keywords["true"] = noIndentEffect keywords["while"] = noIndentEffect keywords["until"] = indentLeft keywords["elseif"] = indentLeft keywords["end"] = indentLeft keywords["do"] = indentRight keywords["then"] = indentRight keywords["repeat"] = indentRight keywords["function"] = indentRight keywords["else"] = indentBoth tokenIndentation = {} lib.tokenIndentation = tokenIndentation tokenIndentation[tokens.TOKEN_LEFTPAREN] = indentRight tokenIndentation[tokens.TOKEN_LEFTBRACKET] = indentRight tokenIndentation[tokens.TOKEN_LEFTWING] = indentRight tokenIndentation[tokens.TOKEN_RIGHTPAREN] = indentLeft tokenIndentation[tokens.TOKEN_RIGHTBRACKET] = indentLeft tokenIndentation[tokens.TOKEN_RIGHTWING] = indentLeft local function fillWithTabs(n) return stringrep("\t", n) end local function fillWithSpaces(a, b) return stringrep(" ", a*b) end local defaultColorTable function lib.colorCodeCode(code, colorTable) local stopColor = colorTable and colorTable[0] if not stopColor then return {}, 0 end local formatTable = {} local totalLen = 0 local numLines = 0 local prevTokenWasColored = false local prevTokenWidth = 0 local pos = 1 local level = 0 while true do prevTokenWasColored = false prevTokenWidth = 0 local tokenType, nextPos = nextToken(code, pos) if not tokenType then break end if tokenType == tokens.TOKEN_UNKNOWN then -- ignore color codes elseif tokenType == tokens.TOKEN_LINEBREAK or tokenType == tokens.TOKEN_WHITESPACE then if tokenType == tokens.TOKEN_LINEBREAK then numLines = numLines + 1 end local str = stringsub(code, pos, nextPos - 1) prevTokenWidth = nextPos - pos totalLen = totalLen + stringlen(str) else local str = stringsub(code, pos, nextPos - 1) prevTokenWidth = nextPos - pos -- Add coloring if keywords[str] then tokenType = tokens.TOKEN_KEYWORD end local color if stopColor then color = colorTable[str] or defaultColorTable[str] if not color then color = colorTable[tokenType] or defaultColorTable[tokenType] if not color then if tokenType == tokens.TOKEN_IDENTIFIER then color = colorTable[tokens.TOKEN_IDENTIFIER] or defaultColorTable[tokens.TOKEN_IDENTIFIER] else color = colorTable[tokens.TOKEN_SPECIAL] or defaultColorTable[tokens.TOKEN_SPECIAL] end end end end if color then table.insert(formatTable, { pos = totalLen, val = color }) totalLen = totalLen + (nextPos - pos) table.insert(formatTable, { pos = totalLen, val = stopColor }) prevTokenWasColored = true else totalLen = totalLen + stringlen(str) end end pos = nextPos end return formatTable, numLines end function lib.indentCode(code, tabWidth, colorTable, caretPosition) local fillFunction if tabWidth == nil then tabWidth = defaultTabWidth end if tabWidth then fillFunction = fillWithSpaces else fillFunction = fillWithTabs end tableclear(workingTable) local tsize = 0 local totalLen = 0 tableclear(workingTable2) local tsize2 = 0 local totalLen2 = 0 local formatTable = {} local stopColor = colorTable and colorTable[0] local newCaretPosition local newCaretPositionFinalized = false local prevTokenWasColored = false local prevTokenWidth = 0 local pos = 1 local level = 0 local hitNonWhitespace = false local hitIndentRight = false local preIndent = 0 local postIndent = 0 while true do if caretPosition and not newCaretPosition and pos >= caretPosition then if pos == caretPosition then newCaretPosition = totalLen + totalLen2 else newCaretPosition = totalLen + totalLen2 local diff = pos - caretPosition if diff > prevTokenWidth then diff = prevTokenWidth end newCaretPosition = newCaretPosition - diff end end prevTokenWasColored = false prevTokenWidth = 0 local tokenType, nextPos = nextToken(code, pos) if not tokenType or tokenType == tokens.TOKEN_LINEBREAK then level = level + preIndent if level < 0 then level = 0 end local s = fillFunction(level, tabWidth) tsize = tsize + 1 workingTable[tsize] = s totalLen = totalLen + stringlen(s) if newCaretPosition and not newCaretPositionFinalized then newCaretPosition = newCaretPosition + stringlen(s) newCaretPositionFinalized = true end for k, v in next,workingTable2 do if stringsub(v, 1, 2) == "|c" then table.insert(formatTable, { pos = totalLen, val = stringsub(v, 3) }) else tsize = tsize + 1 workingTable[tsize] = v totalLen = totalLen + stringlen(v) end end if not tokenType then break end tsize = tsize + 1 workingTable[tsize] = stringsub(code, pos, nextPos - 1) totalLen = totalLen + nextPos - pos level = level + postIndent if level < 0 then level = 0 end tableclear(workingTable2) tsize2 = 0 totalLen2 = 0 hitNonWhitespace = false hitIndentRight = false preIndent = 0 postIndent = 0 elseif tokenType == tokens.TOKEN_WHITESPACE then if hitNonWhitespace then prevTokenWidth = nextPos - pos tsize2 = tsize2 + 1 local s = stringsub(code, pos, nextPos - 1) workingTable2[tsize2] = s totalLen2 = totalLen2 + stringlen(s) end elseif tokenType == tokens.TOKEN_UNKNOWN then -- skip these, though they shouldn't be encountered here anyway else hitNonWhitespace = true local str = stringsub(code, pos, nextPos - 1) prevTokenWidth = nextPos - pos -- See if this is an indent-modifier local indentTable if tokenType == tokens.TOKEN_IDENTIFIER then indentTable = keywords[str] else indentTable = tokenIndentation[tokenType] end if indentTable then if hitIndentRight then postIndent = postIndent + indentTable[1] + indentTable[2] else local pre = indentTable[1] local post = indentTable[2] if post > 0 then hitIndentRight = true end preIndent = preIndent + pre postIndent = postIndent + post end end -- Add coloring if keywords[str] then tokenType = tokens.TOKEN_KEYWORD end local color if stopColor then color = colorTable[str] or defaultColorTable[str] if not color then color = colorTable[tokenType] or defaultColorTable[tokenType] if not color then if tokenType == tokens.TOKEN_IDENTIFIER then color = colorTable[tokens.TOKEN_IDENTIFIER] or defaultColorTable[tokens.TOKEN_IDENTIFIER] else color = colorTable[tokens.TOKEN_SPECIAL] or defaultColorTable[tokens.TOKEN_SPECIAL] end end end end if color then tsize2 = tsize2 + 1 workingTable2[tsize2] = "|c" .. color tsize2 = tsize2 + 1 workingTable2[tsize2] = str totalLen2 = totalLen2 + nextPos - pos tsize2 = tsize2 + 1 workingTable2[tsize2] = "|c" .. stopColor prevTokenWasColored = true else tsize2 = tsize2 + 1 workingTable2[tsize2] = str totalLen2 = totalLen2 + nextPos - pos end end pos = nextPos end return table.concat(workingTable), formatTable, newCaretPosition end local defaultTabWidth = 4 function lib.textboxReindent(textbox) textbox.indenting = true local prevPos, prevColor, v, newCaretPos, formatTable = 0, "0" textbox.value, formatTable, newCaret = lib.indentCode(textbox.value, textbox.tabWidth + 0, textbox.colorTable, textbox.caretpos + 0) local tags = iup.user { bulk = "Yes", cleanout = "Yes" } for i = 1, #formatTable do local v = formatTable[i] if prevPos ~= v.pos and prevColor ~= "0" then iup.Append(tags, iup.user { selectionpos = prevPos .. ":" .. v.pos, fgcolor = prevColor }) end prevPos, prevColor = v.pos, v.val end textbox.addformattag = tags textbox.caretpos = newCaret textbox.indenting = nil end function lib.textboxRecolor(textbox) if textbox.indenting then return end textbox.indenting = true local prevPos, prevColor, oldCaret, v, formatTable = 0, "0", textbox.caretpos formatTable = lib.colorCodeCode(textbox.value, textbox.colorTable) local tags = iup.user { bulk = "Yes", cleanout = "Yes" } for i = 1, #formatTable do local v = formatTable[i] if prevPos ~= v.pos and prevColor ~= "0" then iup.Append(tags, iup.user { selectionpos = prevPos .. ":" .. v.pos, fgcolor = prevColor }) end prevPos, prevColor = v.pos, v.val end textbox.addformattag = tags textbox.caretpos = oldCaret textbox.indenting = nil end function lib.enable(textbox, colorTable, tabWidth) if not colorTable then colorTable = defaultColorTable end if not tabWidth then tabWidth = defaultTabWidth end textbox.colorTable = colorTable textbox.tabWidth = tabWidth textbox.formatting = "Yes" textbox.multiline = "Yes" textbox.timer = iup.timer { action_cb = function(timer) timer.run = "No" -- TODO: optimize this to recolor only in the changed lines lib.textboxRecolor(textbox) end, time = 800 } -- AVOID: redefinition of common callbacks -- textbox.map_cb = function(textbox) -- lib.textboxRecolor(textbox) -- end textbox.valuechanged_cb = function(textbox) textbox.timer.run = "No" -- stop to start again if already running textbox.timer.run = "Yes" end -- AVOID: redefinition of common callbacks -- textbox.k_any = function(textbox, key) -- if key == iup.K_cF then -- lib.textboxReindent(textbox) -- return IUP_IGNORE -- end -- return IUP_CONTINUE -- end end defaultColorTable = {} lib.defaultColorTable = defaultColorTable defaultColorTable[tokens.TOKEN_SPECIAL] = "0 0 192" defaultColorTable[tokens.TOKEN_KEYWORD] = "0 0 255" defaultColorTable[tokens.TOKEN_COMMENT_SHORT] = "0 128 0" defaultColorTable[tokens.TOKEN_COMMENT_LONG] = "0 128 0" local stringColor = "128 128 128" defaultColorTable[tokens.TOKEN_STRING] = stringColor defaultColorTable[".."] = "0 0 128" local tableColor = "0 0 192" defaultColorTable["..."] = tableColor defaultColorTable["{"] = tableColor defaultColorTable["}"] = tableColor defaultColorTable["["] = tableColor defaultColorTable["]"] = tableColor local arithmeticColor = "0 0 192" defaultColorTable[tokens.TOKEN_NUMBER] = "255 128 0" defaultColorTable["+"] = arithmeticColor defaultColorTable["-"] = arithmeticColor defaultColorTable["/"] = arithmeticColor defaultColorTable["*"] = arithmeticColor local logicColor1 = "0 0 192" defaultColorTable["=="] = logicColor1 defaultColorTable["<"] = logicColor1 defaultColorTable["<="] = logicColor1 defaultColorTable[">"] = logicColor1 defaultColorTable[">="] = logicColor1 defaultColorTable["~="] = logicColor1 local logicColor2 = "0 0 255" defaultColorTable["and"] = logicColor2 defaultColorTable["or"] = logicColor2 defaultColorTable["not"] = logicColor2 defaultColorTable[0] = "0" end