diff --git a/FAIAP.lua b/FAIAP.lua new file mode 100755 index 0000000..c9a82c0 --- /dev/null +++ b/FAIAP.lua @@ -0,0 +1,1245 @@ +--[[ +-- For all Indents and Purposes +-- Copyright (c) 2007 Kristofer Karlsson <kristofer.karlsson@gmail.com> +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. +--]] + +-- For All Indents And Purposes - +-- a indentation + syntax highlighting library +-- All valid lua code should be processed correctly. + +-- For both variants: +-- 2) hook the editboxes 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) + +WowLua.indent = {} + +local lib = WowLua.indent +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 + +-- WoW specific tokens +tokens.TOKEN_COLORCODE_START = 37 +tokens.TOKEN_COLORCODE_STOP = 38 + +-- new as of lua 5.1 +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(">") +-- WoW specific chars +bytes.BYTE_VERTICAL = stringbyte("|") +bytes.BYTE_r = stringbyte("r") +bytes.BYTE_c = stringbyte("c") + +-- new as of lua 5.1 +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 +-- WoW specific +specialCharacters[bytes.BYTE_VERTICAL] = -1 +-- new as of lua 5.1 +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 lib.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 + + -- WoW specific (for color codes) + if byte == bytes.BYTE_VERTICAL then + byte = stringbyte(text, pos + 1) + if byte == bytes.BYTE_VERTICAL then + return tokens.TOKEN_VERTICAL, pos + 2 + end + if byte == bytes.BYTE_c then + return tokens.TOKEN_COLORCODE_START, pos + 10 + end + if byte == bytes.BYTE_r then + return tokens.TOKEN_COLORCODE_STOP, pos + 2 + end + return tokens.TOKEN_UNKNOWN, 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 + +local 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 + +function lib.colorCodeCode(code, colorTable, caretPosition) + local stopColor = colorTable and colorTable[0] + if not stopColor then + return code, caretPosition + end + + local stopColorLen = stringlen(stopColor) + + tableclear(workingTable) + local tsize = 0 + local totalLen = 0 + + local numLines = 0 + local newCaretPosition + local prevTokenWasColored = false + local prevTokenWidth = 0 + + local pos = 1 + local level = 0 + + while true do + if caretPosition and not newCaretPosition and pos >= caretPosition then + if pos == caretPosition then + newCaretPosition = totalLen + else + newCaretPosition = totalLen + local diff = pos - caretPosition + if diff > prevTokenWidth then + diff = prevTokenWidth + end + if prevTokenWasColored then + diff = diff + stopColorLen + end + newCaretPosition = newCaretPosition - diff + end + end + + prevTokenWasColored = false + prevTokenWidth = 0 + + local tokenType, nextPos = lib.nextToken(code, pos) + + if not tokenType then + break + end + + if tokenType == tokens.TOKEN_COLORCODE_START or tokenType == tokens.TOKEN_COLORCODE_STOP or 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 + + tsize = tsize + 1 + workingTable[tsize] = str + 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] + if not color then + color = colorTable[tokenType] + if not color then + if tokenType == tokens.TOKEN_IDENTIFIER then + color = colorTable[tokens.TOKEN_IDENTIFIER] + else + color = colorTable[tokens.TOKEN_SPECIAL] + end + end + end + end + + if color then + tsize = tsize + 1 + workingTable[tsize] = color + tsize = tsize + 1 + workingTable[tsize] = str + tsize = tsize + 1 + workingTable[tsize] = stopColor + + totalLen = totalLen + stringlen(color) + (nextPos - pos) + stopColorLen + prevTokenWasColored = true + else + tsize = tsize + 1 + workingTable[tsize] = str + + totalLen = totalLen + stringlen(str) + end + end + + pos = nextPos + end + return table.concat(workingTable), newCaretPosition, 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 stopColor = colorTable and colorTable[0] + local stopColorLen = not stopColor or stringlen(stopColor) + + 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 + if prevTokenWasColored then + diff = diff + stopColorLen + end + newCaretPosition = newCaretPosition - diff + end + end + + prevTokenWasColored = false + prevTokenWidth = 0 + + local tokenType, nextPos = lib.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 + tsize = tsize + 1 + workingTable[tsize] = v + totalLen = totalLen + stringlen(v) + 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_COLORCODE_START or tokenType == tokens.TOKEN_COLORCODE_STOP or 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] + if not color then + color = colorTable[tokenType] + if not color then + if tokenType == tokens.TOKEN_IDENTIFIER then + color = colorTable[tokens.TOKEN_IDENTIFIER] + else + color = colorTable[tokens.TOKEN_SPECIAL] + end + end + end + end + + if color then + tsize2 = tsize2 + 1 + workingTable2[tsize2] = color + totalLen2 = totalLen2 + stringlen(color) + + tsize2 = tsize2 + 1 + workingTable2[tsize2] = str + totalLen2 = totalLen2 + nextPos - pos + + tsize2 = tsize2 + 1 + workingTable2[tsize2] = stopColor + totalLen2 = totalLen2 + stopColorLen + + prevTokenWasColored = true + else + tsize2 = tsize2 + 1 + workingTable2[tsize2] = str + totalLen2 = totalLen2 + nextPos - pos + + end + end + pos = nextPos + end + return table.concat(workingTable), newCaretPosition +end + + + +-- WoW specific code: +local GetTime = GetTime + +local editboxSetText +local editboxGetText + +function lib.stripWowColors(code) + + -- HACK! + -- This is a fix for a bug, where an unfinished string causes a lot of newlines to be created. + -- The reason for the bug, is that a |r\n\n gets converted to \n\n|r after the next indent-run + -- The fix is to remove those last two linebreaks when stripping + code = stringgsub(code, "|r\n\n$", "|r") + + tableclear(workingTable) + local tsize = 0 + + local pos = 1 + + local prevVertical = false + local even = true + local selectionStart = 1 + + while true do + local byte = stringbyte(code, pos) + if not byte then + break + end + if byte == bytes.BYTE_VERTICAL then + even = not even + prevVertical = true + else + if prevVertical and not even then + if byte == bytes.BYTE_c then + + if pos - 2 >= selectionStart then + tsize = tsize + 1 + workingTable[tsize] = stringsub(code, selectionStart, pos - 2) + end + + pos = pos + 8 + selectionStart = pos + 1 + elseif byte == bytes.BYTE_r then + + if pos - 2 >= selectionStart then + tsize = tsize + 1 + workingTable[tsize] = stringsub(code, selectionStart, pos - 2) + end + selectionStart = pos + 1 + end + end + prevVertical = false + even = true + end + pos = pos + 1 + end + if pos >= selectionStart then + tsize = tsize + 1 + workingTable[tsize] = stringsub(code, selectionStart, pos - 1) + end + return table.concat(workingTable) +end + +function lib.decode(code) + if code then + code = lib.stripWowColors(code) + code = stringgsub(code, "||", "|") + end + return code or "" +end + +function lib.encode(code) + if code then + code = stringgsub(code, "|", "||") + end + return code or "" +end + +function lib.stripWowColorsWithPos(code, pos) + code = stringinsert(code, pos, "\2") + code = lib.stripWowColors(code) + pos = stringfind(code, "\2", 1, 1) + code = stringdelete(code, pos, pos) + return code, pos +end + +-- returns the padded code, and true if modified, false if unmodified +local linebreak = stringbyte("\n") +function lib.padWithLinebreaks(code) + do + return code, false + end + + local len = stringlen(code) + if stringbyte(code, len) == linebreak then + if stringbyte(code, len - 1) == linebreak then + return code, false + end + return code .. "\n", true + end + return code .. "\n\n", true + +end + +local defaultTabWidth = 2 +local defaultColorTable + +-- Data tables +-- No weak table magic, since editboxes can never be removed in WoW +local enabled = {} +local dirty = {} + +local editboxIndentCache = {} +local decodeCache = {} +local editboxStringCache = {} +local editboxNumLinesCache = {} + +function lib.coloredGetText(editbox) + return editboxGetText(editbox) +end + +function lib.colorCodeEditbox(editbox) + dirty[editbox] = nil + + local colorTable = editbox.faiap_colorTable or defaultColorTable + local tabWidth = editbox.faiap_tabWidth + + local orgCode = editboxGetText(editbox) + local prevCode = editboxStringCache[editbox] + if prevCode == orgCode then + return + end + + local pos = editbox:GetCursorPosition() + + local code + code, pos = lib.stripWowColorsWithPos(orgCode, pos) + + colorTable[0] = "|r" + + local newCode, newPos, numLines = lib.colorCodeCode(code, colorTable, pos) + if editbox:IsMultiLine() then + newCode = lib.padWithLinebreaks(newCode) + end + + editboxStringCache[editbox] = newCode + if orgCode ~= newCode then + decodeCache[editbox] = nil + local stringlenNewCode = stringlen(newCode) + + editboxSetText(editbox, newCode) + if newPos then + if newPos < 0 then newPos = 0 end + if newPos > stringlenNewCode then newPos = stringlenNewCode end + + editbox:SetCursorPosition(newPos) + end + end + + if editboxNumLinesCache[editbox] ~= numLines then + lib.indentEditbox(editbox) + end + editboxNumLinesCache[editbox] = numLines +end + +function lib.indentEditbox(editbox) + dirty[editbox] = nil + + local colorTable = editbox.faiap_colorTable or defaultColorTable + local tabWidth = editbox.faiap_tabWidth + + local orgCode = editboxGetText(editbox) + local prevCode = editboxIndentCache[editbox] + if prevCode == orgCode then + return + end + + local pos = editbox:GetCursorPosition() + + local code + code, pos = lib.stripWowColorsWithPos(orgCode, pos) + + colorTable[0] = "|r" + local newCode, newPos = lib.indentCode(code, tabWidth, colorTable, pos) + if editbox:IsMultiLine() then + newCode = lib.padWithLinebreaks(newCode) + end + + editboxIndentCache[editbox] = newCode + if code ~= newCode then + decodeCache[editbox] = nil + + local stringlenNewCode = stringlen(newCode) + + editboxSetText(editbox, newCode) + + if newPos then + if newPos < 0 then newPos = 0 end + if newPos > stringlenNewCode then newPos = stringlenNewCode end + + editbox:SetCursorPosition(newPos) + end + end +end + +local function hookHandler(editbox, handler, newFun) + local oldFun = editbox:GetScript(handler) + if oldFun == newFun then + -- already hooked, ignore it + return + end + editbox["faiap_old_" .. handler] = oldFun + editbox:SetScript(handler, newFun) +end + +local function textChangedHook(editbox, ...) + local oldFun = editbox["faiap_old_OnTextChanged"] + if oldFun then + oldFun(editbox, ...) + end + if enabled[editbox] then + dirty[editbox] = GetTime() + end +end + +local function tabPressedHook(editbox, ...) + local oldFun = editbox["faiap_old_OnTabPressed"] + if oldFun then + oldFun(editbox, ...) + end + if enabled[editbox] then + return lib.indentEditbox(editbox) + end +end + +local function onUpdateHook(editbox, ...) + local oldFun = editbox["faiap_old_OnUpdate"] + if oldFun then + oldFun(editbox, ...) + end + if enabled[editbox] then + local now = GetTime() + local lastUpdate = dirty[editbox] or now + if now - lastUpdate > 0.2 then + decodeCache[editbox] = nil + return lib.colorCodeEditbox(editbox) + end + end +end + +local function newGetText(editbox) + local decoded = decodeCache[editbox] + if not decoded then + decoded = lib.decode(editboxGetText(editbox)) + decodeCache[editbox] = decoded + end + return decoded or "" +end + +local function newSetText(editbox, text) + decodeCache[editbox] = nil + if text then + local encoded = lib.encode(text) + + return editboxSetText(editbox, encoded) + end +end + +function lib.enable(editbox, colorTable, tabWidth) + if not editboxSetText then + editboxSetText = editbox.SetText + editboxGetText = editbox.GetText + end + + local modified + if editbox.faiap_colorTable ~= colorTable then + editbox.faiap_colorTable = colorTable + modified = true + end + if editbox.faiap_tabWidth ~= tabWidth then + editbox.faiap_tabWidth = tabWidth + modified = true + end + + if enabled[editbox] then + if modified then + lib.indentEditbox(editbox) + end + return + end + + -- Editbox is possibly hooked, but disabled + enabled[editbox] = true + + editbox.oldMaxBytes = editbox:GetMaxBytes() + editbox.oldMaxLetters = editbox:GetMaxLetters() + editbox:SetMaxBytes(0) + editbox:SetMaxLetters(0) + + editbox.GetText = newGetText + editbox.SetText = newSetText + + hookHandler(editbox, "OnTextChanged", textChangedHook) + hookHandler(editbox, "OnTabPressed", tabPressedHook) + hookHandler(editbox, "OnUpdate", onUpdateHook) + + lib.indentEditbox(editbox) +end + +-- Deprecated function +lib.addSmartCode = lib.enable + +function lib.disable(editbox) + if not enabled[editbox] then + return + end + enabled[editbox] = nil + + -- revert settings for max bytes / letters + editbox:SetMaxBytes(editbox.oldMaxBytes) + editbox:SetMaxLetters(editbox.oldMaxLetters) + + -- try a real unhooking, if possible + if editbox:GetScript("OnTextChanged") == textChangedHook then + editbox:SetScript("OnTextChanged", editbox.faiap_old_OnTextChanged) + editbox.faiap_old_OnTextChanged = nil + end + + if editbox:GetScript("OnTabPressed") == tabPressedHook then + editbox:SetScript("OnTabPressed", editbox.faiap_old_OnTabPressed) + editbox.faiap_old_OnTabPressed = nil + end + + if editbox:GetScript("OnUpdate") == onUpdateHook then + editbox:SetScript("OnUpdate", editbox.faiap_old_OnUpdate) + editbox.faiap_old_OnUpdate = nil + end + + editbox.GetText = nil + editbox.SetText = nil + + -- change the text back to unformatted + editbox:SetText(newGetText(editbox)) + + -- clear caches + editboxIndentCache[editbox] = nil + decodeCache[editbox] = nil + editboxStringCache[editbox] = nil + editboxNumLinesCache[editbox] = nil +end + +defaultColorTable = {} +lib.defaultColorTable = defaultColorTable +defaultColorTable[tokens.TOKEN_SPECIAL] = "|c00ff99ff" +defaultColorTable[tokens.TOKEN_KEYWORD] = "|c006666ff" +defaultColorTable[tokens.TOKEN_COMMENT_SHORT] = "|c00999999" +defaultColorTable[tokens.TOKEN_COMMENT_LONG] = "|c00999999" + +local stringColor = "|c00ffff77" +defaultColorTable[tokens.TOKEN_STRING] = stringColor +defaultColorTable[".."] = stringColor + +local tableColor = "|c00ff9900" +defaultColorTable["..."] = tableColor +defaultColorTable["{"] = tableColor +defaultColorTable["}"] = tableColor +defaultColorTable["["] = tableColor +defaultColorTable["]"] = tableColor + +local arithmeticColor = "|c0033ff55" +defaultColorTable[tokens.TOKEN_NUMBER] = arithmeticColor +defaultColorTable["+"] = arithmeticColor +defaultColorTable["-"] = arithmeticColor +defaultColorTable["/"] = arithmeticColor +defaultColorTable["*"] = arithmeticColor + +local logicColor1 = "|c0055ff88" +defaultColorTable["=="] = logicColor1 +defaultColorTable["<"] = logicColor1 +defaultColorTable["<="] = logicColor1 +defaultColorTable[">"] = logicColor1 +defaultColorTable[">="] = logicColor1 +defaultColorTable["~="] = logicColor1 + +local logicColor2 = "|c0088ffbb" +defaultColorTable["and"] = logicColor2 +defaultColorTable["or"] = logicColor2 +defaultColorTable["not"] = logicColor2 + +defaultColorTable[0] = "|r" diff --git a/WowLua.lua b/WowLua.lua new file mode 100644 index 0000000..f5b4dcf --- /dev/null +++ b/WowLua.lua @@ -0,0 +1,585 @@ +--[[-------------------------------------------------------------------------- + Copyright (c) 2007, James Whitehead II + All rights reserved. + + WowLua is an interactive interpreter for World of Warcraft +--------------------------------------------------------------------------]]-- + +-- TODO: +-- * Make the scroll bars hide/show as necessary +-- * Implement each button as required +-- * Make line numbers line up with soft-wrapped lines +-- * Disable selection of line numbers. Actually, would it be possible to make +-- it select lines a la most other edtiors? +-- * There seems to be a missing background texture in the upper-left 6th or so of the window +-- * Resizing the window should grow the edit box vertically and leave the output window static. +-- * Profit!!! + +WowLua = { + VERSION = "WowLua 1.0 Interactive Interpreter", +} + +WowLuaDB = { + pages = { ["Untitled 1"] = "", [1] = "Untitled 1"}, + currentPage = 1, + untitled = 1, +} + +local function wowpad_print(...) + local out = "" + for i=1,select("#", ...) do + -- Comma seperate values + if i > 1 then + out = out .. ", " + end + + out = out .. tostring(select(i, ...)) + end + WowLuaFrameOutput:AddMessage("|cff999999" .. out .. "|r") +end + +if not print then + print = wowpad_print +end + +local function processSpecialCommands(txt) + if txt == "/reload" then + ReloadUI() + return true + elseif txt == "/reset" then + WowLuaFrame:ClearAllPoints() + WowLuaFrame:SetPoint("CENTER") + WowLuaFrame:SetWidth(640) + WowLuaFrame:SetHeight(512) + WowLuaFrameResizeBar:ClearAllPoints() + WowLuaFrameResizeBar:SetPoint("TOPLEFT", 14, -220) + WowLuaFrameResizeBar:SetPoint("TOPRIGHT", 0, -220) + return true + end +end + +function WowLua:ProcessLine(text) + WowLuaFrameCommandEditBox:SetText("") + + if processSpecialCommands(text) then + return + end + + -- escape any color codes: + local output = text:gsub("\124", "\124\124") + + WowLuaFrameOutput:AddMessage(WowLuaFrameCommandPrompt:GetText() .. output) + + WowLuaFrameCommandEditBox:AddHistoryLine(output) + + -- If they're using "= value" syntax, just print it + text = text:gsub("^%s*=%s*(.+)", "print(%1)") + + -- Store this command into self.cmd in case we have multiple lines + if self.cmd then + self.cmd = self.cmd .. "\n" .. text + self.orig = self.orig .. "\n" .. text + else + self.cmd = text + self.orig = text + end + + -- Trim the command before we run it + self.cmd = string.trim(self.cmd) + + -- Process the current command + local func,err = loadstring(self.cmd) + + -- Fail to compile? Give it a return + -- Check to see if this just needs a return in front of it + if not func then + local newfunc,newerr = loadstring("print(" .. self.cmd .. ")") + if newfunc then + func,err = newfunc,newerr + end + end + + if not func then + -- Check to see if this is just an unfinished block + if err:sub(-7, -1) == "'<eof>'" then + -- Change the prompt + WowLuaFrameCommandPrompt:SetText(">> ") + return + end + + WowLuaFrameOutput:AddMessage("|cffff0000" .. err .. "|r") + self.cmd = nil + WowLuaFrameCommandPrompt:SetText("> ") + else + -- Make print a global function + local old_print = print + print = wowpad_print + + -- Call the function + local succ,err = pcall(func) + + -- Restore the value of print + print = old_print + + if not succ then + WowLuaFrameOutput:AddMessage("|cffff0000" .. err .. "|r") + end + + self.cmd = nil + WowLuaFrameCommandPrompt:SetText("> ") + end +end + +function WowLua.RunScript(text) + -- escape any color codes: + local output = text:gsub("\124", "\124\124") + + if text == "/reload" then + ReloadUI() + end + + -- If they're using "= value" syntax, just print it + text = text:gsub("^%s*=%s*(.+)", "print(%1)") + + -- Trim the command before we run it + text = string.trim(text) + + -- Process the current command + local func,err = loadstring(text, "WowLua") + + if not func then + WowLuaFrameOutput:AddMessage("|cffff0000" .. err .. "|r") + return false, err + else + -- Make print a global function + local old_print = print + print = wowpad_print + + -- Call the function + local succ,err = pcall(func) + + -- Restore the value of print + print = old_print + + if not succ then + WowLuaFrameOutput:AddMessage("|cffff0000" .. err .. "|r") + return false, err + end + end + + return true +end + +function WowLua.Initialize(self) + WowLua.OnSizeChanged(self) + table.insert(UISpecialFrames, "WowLuaFrame") + PlaySound("igMainMenuOpen"); +end + +local tooltips = { + ["New"] = "Create a new script page", + ["Open"] = "Open an existing script page", + ["Save As"] = "Save the current page with a name", + ["Undo"] = "Revert to the last saved version", + ["Delete"] = "Delete the current page", + ["Lock"] = "Locks/unlocks the current page from being changed", + ["Previous"] = "Navigate back one page", + ["Next"] = "Navigate forward one page", + ["Run"] = "Run the current script", +} + +function WowLua.Button_OnEnter(self) + GameTooltip:SetOwner(this, "ANCHOR_BOTTOM"); + local operation = self:GetName():match("WowLuaButton_(.+)"):gsub("_", " ") + GameTooltip:SetText(operation) + if tooltips[operation] then + GameTooltip:AddLine(tooltips[operation], 1, 1, 1) + end + GameTooltip:Show(); +end + +function WowLua.Button_OnLeave(self) + GameTooltip:Hide() +end + +function WowLua.Button_OnClick(self) + local operation = self:GetName():match("WowLuaButton_(.+)") + if operation == "New" then + local page = WowLuaDB.pages[WowLuaDB.currentPage] + local text = WowLuaFrameEditBox:GetText() + WowLuaDB.pages[page] = text + WowLuaFrameEditBox:SetText("") + WowLuaDB.untitled = WowLuaDB.untitled + 1 + WowLuaDB.pages[#WowLuaDB.pages + 1] = string.format("Untitled %d", WowLuaDB.untitled) + WowLuaDB.currentPage = #WowLuaDB.pages + WowLuaButton_Next:Disable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),true) + WowLuaButton_Previous:Enable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),false) + elseif operation == "Open" then + elseif operation == "Save_As" then + elseif operation == "Undo" then + local page = WowLuaDB.pages[WowLuaDB.currentPage] + WowLuaFrameEditBox:SetText(WowLuaDB.pages[page]) + elseif operation == "Delete" then + local page = WowLuaDB.pages[WowLuaDB.currentPage] + WowLuaDB.pages[page] = nil + table.remove(WowLuaDB.pages, WowLuaDB.currentPage) + if WowLuaDB.currentPage > 1 then + WowLuaDB.currentPage = WowLuaDB.currentPage - 1 + end + local page = WowLuaDB.pages[WowLuaDB.currentPage] + WowLuaFrameEditBox:SetText(WowLuaDB.pages[page]) + if WowLuaDB.currentPage == 1 then + WowLuaButton_Previous:Disable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),true) + else + WowLuaButton_Previous:Enable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),false) + end + if WowLuaDB.currentPage == #WowLuaDB.pages then + WowLuaButton_Next:Disable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),true) + else + WowLuaButton_Next:Enable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),false) + end + elseif operation == "Lock" then + elseif operation == "Previous" then + local cPage = WowLuaDB.pages[WowLuaDB.currentPage] + local text = WowLuaFrameEditBox:GetText() + WowLuaDB.pages[cPage] = text + WowLuaDB.currentPage = WowLuaDB.currentPage - 1 + cPage = WowLuaDB.pages[WowLuaDB.currentPage] + WowLuaFrameEditBox:SetText(WowLuaDB.pages[cPage] or "") + if WowLuaDB.currentPage == 1 then + WowLuaButton_Previous:Disable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),true) + else + WowLuaButton_Previous:Enable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),false) + end + if WowLuaDB.currentPage == #WowLuaDB.pages then + WowLuaButton_Next:Disable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),true) + else + WowLuaButton_Next:Enable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),false) + end + elseif operation == "Next" then + local cPage = WowLuaDB.pages[WowLuaDB.currentPage] + local text = WowLuaFrameEditBox:GetText() + WowLuaDB.pages[cPage] = text + WowLuaDB.currentPage = WowLuaDB.currentPage + 1 + cPage = WowLuaDB.pages[WowLuaDB.currentPage] + WowLuaFrameEditBox:SetText(WowLuaDB.pages[cPage] or "") + if WowLuaDB.currentPage == #WowLuaDB.pages then + WowLuaButton_Next:Disable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),true) + else + WowLuaButton_Next:Enable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),true) + end + if WowLuaDB.currentPage == 1 then + WowLuaButton_Previous:Disable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),true) + else + WowLuaButton_Previous:Enable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),true) + end + elseif operation == "Run" then + -- Run the script, if there is an error then highlight it + local text = WowLuaFrameEditBox:GetText() + if text then + local succ,err = WowLua.RunScript(text) + if not succ then + local chunkName,lineNum = err:match("(%b[]):(%d+):") + lineNum = tonumber(lineNum) + WowLua.UpdateLineNums(lineNum) + + -- Highlight the text in the editor by finding the char of the line number we're on + text = WowLua.indent.coloredGetText(WowLuaFrameEditBox) + + local curLine,start = 1,1 + while curLine < lineNum do + local s,e = text:find("\n", start) + start = e + 1 + curLine = curLine + 1 + end + + local nextLine = select(2, text:find("\n", start)) + + WowLuaFrameEditBox:SetFocus() + WowLuaFrameEditBox:SetCursorPosition(start - 1) + end + local page = WowLuaDB.pages[WowLuaDB.currentPage] + WowLuaDB.pages[page] = text + end + end +end + +local function slashHandler(txt) + local page = WowLuaDB.pages[WowLuaDB.currentPage] + WowLuaFrameEditBox:SetText(WowLuaDB.pages[page]) + if WowLuaDB.currentPage == 1 then + WowLuaButton_Previous:Disable() + SetDesaturation(WowLuaButton_Previous:GetNormalTexture(),true) + end + if WowLuaDB.currentPage == #WowLuaDB.pages then + WowLuaButton_Next:Disable() + SetDesaturation(WowLuaButton_Next:GetNormalTexture(),true) + end + --WowLua:CreateFrame() + WowLuaFrame:Show() + + if processSpecialCommands(txt) then + return + end + + if txt:match("%S") then + WowLua:ProcessLine(txt) + end + + WowLuaFrameCommandEditBox:SetFocus() +end + +SLASH_WOWLUA1 = "/wowlua" +SLASH_WOWLUA2 = "/lua" +SlashCmdList["WOWLUA"] = slashHandler + +function WowLua.OnSizeChanged(self) + -- The first graphic is offset 13 pixels to the right + local width = self:GetWidth() - 13 + local bg2w,bg3w,bg4w = 0,0,0 + + -- Resize bg2 up to 256 width + local bg2w = width - 256 + if bg2w > 256 then + bg3w = bg2w - 256 + bg2w = 256 + end + + if bg3w > 256 then + bg4w = bg3w - 256 + bg3w = 256 + end + + local bg2 = WowLuaFrameBG2 + local bg3 = WowLuaFrameBG3 + local bg4 = WowLuaFrameBG4 + + if bg2w > 0 then + bg2:SetWidth(bg2w) + bg2:SetTexCoord(0, (bg2w / 256), 0, 1) + bg2:Show() + else + bg2:Hide() + end + + if bg3w and bg3w > 0 then + bg3:SetWidth(bg3w) + bg3:SetTexCoord(0, (bg3w / 256), 0, 1) + bg3:Show() + else + bg3:Hide() + end + + if bg4w and bg4w > 0 then + bg4:SetWidth(bg4w) + bg4:SetTexCoord(0, (bg4w / 256), 0, 1) + bg4:Show() + else + bg4:Hide() + end + + if WowLuaFrameResizeBar then + -- Don't move too high, or too low + local parent = WowLuaFrameResizeBar:GetParent() + local top = parent:GetTop() + local bot = parent:GetBottom() + local maxpoint = (top - bot - 80) * -1 + + -- This is the current point, actually + + local newPoint = select(5, WowLuaFrameResizeBar:GetPoint()) + + -- Don't move past the edges of the frame + if newPoint < maxpoint then + newPoint = maxpoint + elseif newPoint > -125 then + newPoint = -125 + end + + WowLuaFrameResizeBar:ClearAllPoints() + WowLuaFrameResizeBar:SetPoint("TOPLEFT", 14, newPoint) + WowLuaFrameResizeBar:SetPoint("TOPRIGHT", 0, newPoint) + + --[[ + -- Get our bottom, and the bottom of the frame + local sbot,pbot = WowLuaFrameResizeBar:GetBottom(), parent:GetBottom() + -- Diff + local diff = pbot - sbot + local numLines = math.abs((diff / 14) + 1.3) + if numLines <= 1 then numLines = 1 end + WowLuaFrameOutput:SetMaxLines(numLines) + --]] + end +end + +function WowLua.ResizeBar_OnMouseDown(self, button) + self.cursorStart = select(2, GetCursorPosition()) + self.anchorStart = select(5, self:GetPoint()) + self:SetScript("OnUpdate", WowLua.ResizeBar_OnUpdate) +end + +function WowLua.ResizeBar_OnMouseUp(self, button) + self:SetScript("OnUpdate", nil) +end + +function WowLua.ResizeBar_OnUpdate(self, elapsed) + local cursorY = select(2, GetCursorPosition()) + local newPoint = self.anchorStart - (self.cursorStart - cursorY)/self:GetEffectiveScale() + + -- Don't move too high, or too low + local parent = self:GetParent() + local top = parent:GetTop() + local bot = parent:GetBottom() + local maxpoint = (top - bot - 80) * -1 + + -- Don't move past the edges of the frame + if newPoint < maxpoint then + newPoint = maxpoint + elseif newPoint > -125 then + newPoint = -125 + end + + self:ClearAllPoints() + self:SetPoint("TOPLEFT", 14, newPoint) + self:SetPoint("TOPRIGHT", 0, newPoint) + + --[[ + -- Get our bottom, and the bottom of the frame + local sbot,pbot = self:GetBottom(), parent:GetBottom() + -- Diff + local diff = pbot - sbot + local numLines = math.abs((diff / 14) + 1.3) + if numLines <= 1 then numLines = 1 end + WowLuaFrameOutput:SetMaxLines(numLines) + --]] +end + +function WowLua.OnVerticalScroll(scrollFrame) + local offset = scrollFrame:GetVerticalScroll(); + local scrollbar = getglobal(scrollFrame:GetName().."ScrollBar"); + + scrollbar:SetValue(offset); + local min, max = scrollbar:GetMinMaxValues(); + local display = false; + if ( offset == 0 ) then + getglobal(scrollbar:GetName().."ScrollUpButton"):Disable(); + else + getglobal(scrollbar:GetName().."ScrollUpButton"):Enable(); + display = true; + end + if ((scrollbar:GetValue() - max) == 0) then + getglobal(scrollbar:GetName().."ScrollDownButton"):Disable(); + else + getglobal(scrollbar:GetName().."ScrollDownButton"):Enable(); + display = true; + end + if ( display ) then + scrollbar:Show(); + else + scrollbar:Hide(); + end +end + +function WowLua.UpdateLineNums(highlightNum) + local text = WowLuaFrameEditBox:GetText() + + highlightNum = highlightNum or WowLuaFrameEditBox.highlightNum + + local lineText = "" + local count = 1 + + if count == highlightNum then + lineText = lineText .. "|cFFFF1111" .. count .. "|r" .. "\n" + else + lineText = lineText .. count .. "\n" + end + + count = count + 1 + + for line in WowLuaFrameEditBox:GetText():gmatch("\n") do + if count == highlightNum then + lineText = lineText .. "|cFFFF1111" .. count .. "|r" .. "\n" + else + lineText = lineText .. count .. "\n" + end + + count = count + 1 + end + WowLuaFrameLineNumEditBox:SetText(lineText) + WowLuaFrameEditBox.oldtext = text + WowLuaFrameEditBox.highlightNum = highlightNum +end + +local function canScroll(scroll, direction) + local num, displayed, currScroll = scroll:GetNumMessages(), + scroll:GetNumLinesDisplayed(), + scroll:GetCurrentScroll(); + if ( direction == "up" and + ( + num == displayed or + num == ( currScroll + displayed ) + ) + ) then + return false; + elseif ( direction == "down" and currScroll == 0 ) then + return false; + end + return true; +end + +function WowLua.UpdateScrollingMessageFrame(frame) + local name = frame:GetName(); + local display = false; + + if ( canScroll(frame, "up") ) then + getglobal(name.."UpButton"):Enable(); + display = true; + else + getglobal(name.."UpButton"):Disable(); + end + + if ( canScroll(frame, "down") ) then + getglobal(name.."DownButton"):Enable(); + display = true; + else + getglobal(name.."DownButton"):Disable(); + end + + if ( display ) then + getglobal(name.."UpButton"):Show(); + getglobal(name.."DownButton"):Show(); + else + getglobal(name.."UpButton"):Hide(); + getglobal(name.."DownButton"):Hide(); + end +end + +local scrollMethods = { + ["line"] = { ["up"] = "ScrollUp", ["down"] = "ScrollDown" }, + ["page"] = { ["up"] = "PageUp", ["down"] = "PageDown" }, + ["end"] = { ["up"] = "ScrollToTop", ["down"] = "ScrollToBottom" }, +}; + +function WowLua.ScrollingMessageFrameScroll(scroll, direction, type) + -- Make sure we can scroll first + if ( not canScroll(scroll, direction) ) then + return; + end + local method = scrollMethods[type][direction]; + scroll[method](scroll); +end + diff --git a/WowLua.toc b/WowLua.toc new file mode 100644 index 0000000..43503a9 --- /dev/null +++ b/WowLua.toc @@ -0,0 +1,10 @@ +## Interface: 20300 +## Title: WowLua +## Author: Cladhaire +## Notes: Simple interactive Lua interpreter and scratchpad +## SavedVariables: WowLuaDB + +WowLua.lua +WowLuaFrame.lua +FAIAP.lua +WowLua.xml diff --git a/WowLua.xml b/WowLua.xml new file mode 100644 index 0000000..070f770 --- /dev/null +++ b/WowLua.xml @@ -0,0 +1,600 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +../UI.xsd"> + <Button name="WowLuaButtonTemplate" virtual="true"> + <Size x="25" y="25"/> + <Scripts> + <OnClick> + WowLua.Button_OnClick(self, button) + </OnClick> + <OnEnter> + WowLua.Button_OnEnter(self) + </OnEnter> + <OnLeave> + WowLua.Button_OnLeave(self) + </OnLeave> + </Scripts> + </Button> + + <Frame name="WowLuaFrame" toplevel="true" movable="true" parent="UIParent" enableMouse="true" resizable="true" frameStrata="MEDIUM"> + <Size x="640" y="512"/> + <Anchors> + <Anchor point="CENTER"/> + </Anchors> + <ResizeBounds> + <minResize x="365" y="300"/> + </ResizeBounds> + <Layers> + <Layer level="BACKGROUND"> + <Texture name="$parentBG1" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopBackground"> + <Size x="256" y="64"/> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="13" y="-18"/> + </Anchor> + </Anchors> + </Texture> + <Texture name="$parentBG2" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopBackground"> + <Size x="256" y="64"/> + <Anchors> + <Anchor point="LEFT" relativeTo="$parentBG1" relativePoint="RIGHT"/> + </Anchors> + </Texture> + <Texture name="$parentBG3" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopBackground"> + <Size x="256" y="64"/> + <Anchors> + <Anchor point="LEFT" relativeTo="$parentBG2" relativePoint="RIGHT"/> + </Anchors> + </Texture> + <Texture name="$parentBG4" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopBackground"> + <Size x="256" y="64"/> + <Anchors> + <Anchor point="LEFT" relativeTo="$parentBG3" relativePoint="RIGHT"/> + </Anchors> + </Texture> + </Layer> + <Layer level="ARTWORK"> + <Texture name="$parentTopLeft" file="Interface\AddOns\WowLua\images\LightHeaded\TopLeft"> + <Size x="128" y="256"/> + <Anchors> + <Anchor point="TOPLEFT"/> + </Anchors> + </Texture> + <Texture name="$parentTopRight" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopRight"> + <Size x="140" y="242"/> + <Anchors> + <Anchor point="TOPRIGHT"> + <Offset x="0" y="-14"/> + </Anchor> + </Anchors> + <TexCoords left="0" right="0.546875" top="0" bottom="0.9453125"/> + </Texture> + <Texture file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-Top"> + <Size y="242"/> + <Anchors> + <Anchor point="TOPLEFT" relativeTo="$parentTopLeft" relativePoint="TOPRIGHT"> + <Offset x="0" y="-14"/> + </Anchor> + <Anchor point="TOPRIGHT" relativeTo="$parentTopRight" relativePoint="TOPLEFT"> + <Offset x="0" y="0"/> + </Anchor> + </Anchors> + <TexCoords left="0.3" right="0.35" top="0" bottom="0.9453125"/> + </Texture> + <Texture name="$parentBotLeft" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-BotLeft"> + <Size x="128" y="168"/> + <Anchors> + <Anchor point="BOTTOMLEFT"> + <Offset x="8" y="0"/> + </Anchor> + </Anchors> + <TexCoords left="0" right="1" top="0" bottom="0.65625"/> + </Texture> + <Texture name="$parentBotRight" file="Interface\WorldStateframe\WorldStateFinalScoreFrame-BotRight"> + <Size x="140" y="168"/> + <Anchors> + <Anchor point="BOTTOMRIGHT"/> + </Anchors> + <TexCoords left="0" right="0.546875" top="0" bottom="0.65625"/> + </Texture> + <Texture file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-BotLeft"> + <Size y="168"/> + <Anchors> + <Anchor point="TOPLEFT" relativeTo="$parentBotLeft" relativePoint="TOPRIGHT"/> + <Anchor point="TOPRIGHT" relativeTo="$parentBotRight" relativePoint="TOPLEFT"/> + </Anchors> + <TexCoords left="0.25" right="0.5" top="0" bottom="0.65625"/> + </Texture> + <Texture name="$parentMidLeft" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopLeft"> + <Size x="128" y="10"/> + <Anchors> + <Anchor point="TOPLEFT" relativeTo="$parentTopLeft" relativePoint="BOTTOMLEFT"> + <Offset x="8" y="0"/> + </Anchor> + <Anchor point="BOTTOMLEFT" relativeTo="$parentBotLeft" relativePoint="TOPLEFT"> + <Offset x="8" y="0"/> + </Anchor> + </Anchors> + <TexCoords left="0" right="1" top="0.9375" bottom="1"/> + </Texture> + <Texture name="$parentMidRight" file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopRight"> + <Size x="140" y="10"/> + <Anchors> + <Anchor point="TOPRIGHT" relativeTo="$parentTopRight" relativePoint="BOTTOMRIGHT"/> + <Anchor point="BOTTOMRIGHT" relativeTo="$parentBotRight" relativePoint="TOPRIGHT"/> + </Anchors> + <TexCoords left="0" right="0.546875" top="0.9375" bottom="1"/> + </Texture> + <Texture file="Interface\WorldStateFrame\WorldStateFinalScoreFrame-TopLeft"> + <Anchors> + <Anchor point="TOPLEFT" relativeTo="$parentMidLeft" relativePoint="TOPRIGHT"/> + <Anchor point="BOTTOMRIGHT" relativeTo="$parentMidRight" relativePoint="BOTTOMLEFT"/> + </Anchors> + <TexCoords left="0.25" right="0.5" top="0.25" bottom="0.5"/> + </Texture> + <FontString name="$parentTitle" inherits="GameFontNormal" text="WowLua Editor"> + <Anchors> + <Anchor point="TOP"> + <Offset x="15" y="-19"/> + </Anchor> + </Anchors> + </FontString> + </Layer> + <Layer level="BORDER"> + <Texture file="Interface\MacroFrame\MacroFrame-Icon"> + <Size x="60" y="60"/> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="7" y="-6"/> + </Anchor> + </Anchors> + </Texture> + </Layer> + </Layers> + <Frames> + <Button name="$parentClose" inherits="UIPanelCloseButton"> + <Anchors> + <Anchor point="TOPRIGHT"> + <Offset x="5" y="-10"/> + </Anchor> + </Anchors> + </Button> + <Button name="$parentDragHeader"> + <Size y="60"/> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="0" y="-13"/> + </Anchor> + <Anchor point="TOPRIGHT"> + <Offset x="0" y="0"/> + </Anchor> + </Anchors> + <Frames> + <Frame name="WowLuaFrameToolbar"> + <Size y="30"/> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="80" y="-26"/> + </Anchor> + <Anchor point="TOPRIGHT"> + <Offset x="-5" y="-26"/> + </Anchor> + </Anchors> + <!-- Used for placement + <Layers> + <Layer level="ARTWORK"> + <Texture setAllPoints="true"> + <Color r="1" g="0.2" b="0.2" a="0.5"/> + </Texture> + </Layer> + </Layers> + --> + <Frames> + <Button name="WowLuaButton_New" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT"/> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\new"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Open" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_New" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\open"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Save_As" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_Open" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\save"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Undo" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_Save_As" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\undo"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Delete" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_Undo" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\delete"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Lock" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_Delete" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\padlock"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Previous" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_Lock" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\left"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Next" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_Previous" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\right"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + <Button name="WowLuaButton_Run" inherits="WowLuaButtonTemplate"> + <Anchors> + <Anchor point="LEFT" relativeTo="WowLuaButton_Next" relativePoint="RIGHT"> + <Offset x="5" y="0"/> + </Anchor> + </Anchors> + <NormalTexture file="Interface\AddOns\WowLua\images\icons\run-1"/> + <HighlightTexture file="Interface\AddOns\WowLua\images\icons\highlight"/> + </Button> + </Frames> + </Frame> + + </Frames> + <Scripts> + <OnMouseDown> + local parent = self:GetParent() + if parent:IsMovable() then + parent:StartMoving() + end + </OnMouseDown> + <OnMouseUp> + local parent = self:GetParent() + parent:StopMovingOrSizing() + </OnMouseUp> + </Scripts> + </Button> + <Button name="$parentResizeBar"> + <Size y="16"/> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="14" y="-220"/> + </Anchor> + <Anchor point="TOPRIGHT"> + <Offset x="0" y="-220"/> + </Anchor> + </Anchors> + <Layers> + <Layer level="BORDER"> + <Texture name="$parentLeftNub" file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar"> + <Size x="75" y="16"/> + <Anchors> + <Anchor point="LEFT"> + <Offset x="-1"/> + </Anchor> + </Anchors> + <TexCoords left="0" right="0.29296875" top="0" bottom="0.25"/> + </Texture> + <Texture name="$parentRightNub" file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar"> + <Size x="75" y="16"/> + <Anchors> + <Anchor point="RIGHT"> + <Offset x="1"/> + </Anchor> + </Anchors> + <TexCoords left="0" right="0.29296875" top="0.25" bottom="0.5"/> + </Texture> + <Texture name="$parentBar" file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar"> + <Size y="16"/> + <Anchors> + <Anchor point="LEFT" relativeTo="$parentLeftNub" relativePoint="RIGHT"/> + <Anchor point="RIGHT" relativeTo="$parentRightNub" relativePoint="LEFT"/> + </Anchors> + <TexCoords left="0.29296875" right="1.0" top="0" bottom="0.25"/> + </Texture> + </Layer> + </Layers> + <Scripts> + <OnMouseDown> + WowLua.ResizeBar_OnMouseDown(self, button) + </OnMouseDown> + <OnMouseUp> + WowLua.ResizeBar_OnMouseUp(self, button) + </OnMouseUp> + </Scripts> + </Button> + <Button name="$parentResizeCorner"> + <Size x="16" y="16"/> + <Anchors> + <Anchor point="BOTTOMRIGHT"> + <Offset x="-3" y="3"/> + </Anchor> + </Anchors> + <Scripts> + <OnMouseDown> + self:GetParent():StartSizing() + </OnMouseDown> + <OnLoad> + self:GetNormalTexture():SetVertexColor(0.6, 0.6, 0.6) + </OnLoad> + <OnMouseUp> + self:GetParent():StopMovingOrSizing() + if WowLuaFrameEditBox then + WowLuaFrameEditBox:SetWidth(WowLuaFrameEditScrollFrame:GetWidth()) + end + </OnMouseUp> + <OnHide> + self:GetParent():StopMovingOrSizing() + if WowLuaFrameEditBox then + WowLuaFrameEditBox:SetWidth(WowLuaFrameEditScrollFrame:GetWidth()) + end + </OnHide> + </Scripts> + <NormalTexture file="Interface\AddOns\WowLua\images\resize"/> + </Button> + <ScrollFrame name="$parentLineNumScrollFrame"> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="18" y="-74"/> + </Anchor> + <Anchor point="BOTTOMRIGHT" relativeTo="$parentResizeBar" relativePoint="TOPLEFT"> + <Offset x="30" y="-4"/> + </Anchor> + </Anchors> + <Layers> + <Layer level="ARTWORK"> + <Texture setAllPoints="true"><Color r="0.1" g="0.1" b="0.1" a="0.85"/></Texture> + </Layer> + </Layers> + <!-- Basically copy/pasted from MacroFrame --> + <ScrollChild> + <EditBox name="WowLuaFrameLineNumEditBox" multiLine="true" maxLines="9999" letters="4096" nonspacewrap="true" spacing="1" autoFocus="false"> + <Size> + <AbsDimension x="100" y="100"/> + </Size> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="20" y="0"/> + </Anchor> + <Anchor point="BOTTOMRIGHT"/> + </Anchors> + <FontString font="Interface\AddOns\WowLua\fonts\VeraMono.ttf"> + <FontHeight val="14"/> + </FontString> + </EditBox> + </ScrollChild> + </ScrollFrame> + <ScrollFrame name="$parentEditScrollFrame" inherits="UIPanelScrollFrameTemplate"> + <Anchors> + <Anchor point="TOPLEFT" relativeTo="$parentLineNumScrollFrame" relativePoint="TOPRIGHT"> + <Offset x="0" y="0"/> + </Anchor> + <Anchor point="BOTTOMRIGHT" relativeTo="$parentResizeBar" relativePoint="TOPRIGHT"> + <Offset x="-25" y="-4"/> + </Anchor> + </Anchors> + <!-- Basically copy/pasted from MacroFrame --> + <Scripts> + <OnVerticalScroll> + WowLuaFrameLineNumScrollFrame:SetVerticalScroll(offset) + WowLua.OnVerticalScroll(self); + </OnVerticalScroll> + <OnShow> + WowLua.OnVerticalScroll(self); + </OnShow> + <OnLoad> + self.scrollBarHideable = 1; + </OnLoad> + </Scripts> + <ScrollChild> + <EditBox name="WowLuaFrameEditBox" multiLine="true" nonspacewrap="true" spacing="1" autoFocus="false"> + <Size> + <AbsDimension x="100" y="100"/> + </Size> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="20" y="0"/> + </Anchor> + <Anchor point="BOTTOMRIGHT"/> + </Anchors> + <Scripts> + <OnLoad> + WowLua.indent.enable(self, nil, 3) + </OnLoad> + <OnEscapePressed> + self:ClearFocus(); + </OnEscapePressed> + <OnTextChanged> + self.highlightNum = nil + </OnTextChanged> + <OnCursorChanged> + ScrollingEdit_OnCursorChanged(x,y,w,h) + WowLua.UpdateLineNums() + WowLuaFrameEditScrollFrameScrollBar:SetValue(WowLuaFrameEditScrollFrame:GetVerticalScroll()) + </OnCursorChanged> + <OnUpdate> + ScrollingEdit_OnUpdate(WowLuaFrameEditScrollFrame) + </OnUpdate> + </Scripts> + <FontString font="Interface\AddOns\WowLua\fonts\VeraMono.ttf"> + <FontHeight val="14"/> + </FontString> + </EditBox> + </ScrollChild> + </ScrollFrame> + <Button name="$parentEditFocusGrabber"> + <Anchors> + <Anchor point="TOPLEFT"> + <Offset x="18" y="-72"/> + </Anchor> + <Anchor point="BOTTOMRIGHT" relativeTo="$parentResizeBar" relativePoint="TOPRIGHT"> + <Offset x="-30" y="0"/> + </Anchor> + </Anchors> + <Scripts> + <OnClick> + WowLuaFrameEditBox:SetFocus() + </OnClick> + </Scripts> + </Button> + <Frame name="$parentCommand"> + <Size y="16"/> + <Anchors> + <Anchor point="BOTTOMLEFT"> + <Offset x="18" y="3"/> + </Anchor> + <Anchor point="BOTTOMRIGHT"> + <Offset x="-15" y="0"/> + </Anchor> + </Anchors> + <Layers> + <Layer level="BACKGROUND"> + <Texture> + <Anchors> + <Anchor point="TOPLEFT"/> + <Anchor point="BOTTOMRIGHT" relativeTo="WowLuaFrameResizeCorner"> + <Offset x="-3" y="2"/> + </Anchor> + </Anchors> + <Color r="0.1" g="0.1" b="0.1" a="0.85"/> + </Texture> + </Layer> + <Layer level="ARTWORK"> + <FontString name="$parentPrompt" text="> " font="Interface\AddOns\WowLua\fonts\VeraMono.ttf"> + <Anchors> + <Anchor point="LEFT"/> + </Anchors> + <FontHeight val="14"/> + </FontString> + </Layer> + </Layers> + <Frames> + <EditBox name="$parentEditBox" letters="4096" nonspacewrap="true" spacing="1" historyLines="100" autoFocus="false"> + <Anchors> + <Anchor point="TOPLEFT" relativeTo="$parentPrompt" relativePoint="TOPRIGHT"> + <Offset x="5" y="0"/> + </Anchor> + <Anchor point="BOTTOMRIGHT"/> + </Anchors> + <Scripts> + <OnEscapePressed> + self:ClearFocus() + </OnEscapePressed> + <OnTabPressed> + WowLuaFrameEditBox:SetFocus() + </OnTabPressed> + <OnLoad> + WowLua.indent.enable(self) + </OnLoad> + <OnEnterPressed> + WowLua:ProcessLine(self:GetText()) + </OnEnterPressed> + </Scripts> + <FontString font="Interface\AddOns\WowLua\fonts\VeraMono.ttf"> + <FontHeight val="14"/> + </FontString> + </EditBox> + </Frames> + </Frame> + <ScrollingMessageFrame name="$parentOutput" maxLines="9999" fade="false" enableMouse="true"> + <Anchors> + <Anchor point="TOPLEFT" relativeTo="WowLuaFrameResizeBar" relativePoint="BOTTOMLEFT"> + <Offset x="5" y="2"/> + </Anchor> + <Anchor point="BOTTOM" relativeTo="WowLuaFrameCommand" relativePoint="TOP"> + <Offset x="0" y="0"/> + </Anchor> + <Anchor point="RIGHT"> + <Offset x="-4" y="0"/> + </Anchor> + </Anchors> + <Frames> + <Button name="$parentUpButton" inherits="UIPanelScrollUpButtonTemplate"> + <Anchors> + <Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"/> + </Anchors> + <Scripts> + <OnClick> + WowLua.ScrollingMessageFrameScroll(self:GetParent(), "up", "page"); + </OnClick> + </Scripts> + </Button> + <Button name="$parentDownButton" inherits="UIPanelScrollDownButtonTemplate"> + <Anchors> + <Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"/> + </Anchors> + <Scripts> + <OnClick> + WowLua.ScrollingMessageFrameScroll(self:GetParent(), "down", "page"); + </OnClick> + </Scripts> + </Button> + </Frames> + <Scripts> + <OnMouseWheel> + local direction; + if delta > 0 then + direction = "up"; + else + direction = "down"; + end + local type = ( IsShiftKeyDown() and "end" ) or + ( IsControlKeyDown() and "page" ) or "line"; + WowLua.ScrollingMessageFrameScroll(self, direction, type); + </OnMouseWheel> + <OnMessageScrollChanged> + WowLua.UpdateScrollingMessageFrame(self); + </OnMessageScrollChanged> + <OnShow> + WowLua.UpdateScrollingMessageFrame(self); + </OnShow> + </Scripts> + <FontString font="Interface\AddOns\WowLua\fonts\VeraMono.ttf" justifyH="LEFT"> + <FontHeight val="14"/> + </FontString> + </ScrollingMessageFrame> + </Frames> + <Scripts> + <OnShow> + WowLua.Initialize(self) + </OnShow> + <OnHide> + PlaySound("igMainMenuQuit"); + </OnHide> + <OnSizeChanged> + WowLua.OnSizeChanged(self) + </OnSizeChanged> + </Scripts> + </Frame> +</Ui> diff --git a/fonts/COPYRIGHT.TXT b/fonts/COPYRIGHT.TXT new file mode 100644 index 0000000..e651be1 --- /dev/null +++ b/fonts/COPYRIGHT.TXT @@ -0,0 +1,124 @@ +Bitstream Vera Fonts Copyright + +The fonts have a generous copyright, allowing derivative works (as +long as "Bitstream" or "Vera" are not in the names), and full +redistribution (so long as they are not *sold* by themselves). They +can be be bundled, redistributed and sold with any software. + +The fonts are distributed under the following copyright: + +Copyright +========= + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream +Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute +the Font Software, including without limitation the rights to use, +copy, merge, publish, distribute, and/or sell copies of the Font +Software, and to permit persons to whom the Font Software is furnished +to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT +SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font +Software without prior written authorization from the Gnome Foundation +or Bitstream Inc., respectively. For further information, contact: +fonts at gnome dot org. + +Copyright FAQ +============= + + 1. I don't understand the resale restriction... What gives? + + Bitstream is giving away these fonts, but wishes to ensure its + competitors can't just drop the fonts as is into a font sale system + and sell them as is. It seems fair that if Bitstream can't make money + from the Bitstream Vera fonts, their competitors should not be able to + do so either. You can sell the fonts as part of any software package, + however. + + 2. I want to package these fonts separately for distribution and + sale as part of a larger software package or system. Can I do so? + + Yes. A RPM or Debian package is a "larger software package" to begin + with, and you aren't selling them independently by themselves. + See 1. above. + + 3. Are derivative works allowed? + Yes! + + 4. Can I change or add to the font(s)? + Yes, but you must change the name(s) of the font(s). + + 5. Under what terms are derivative works allowed? + + You must change the name(s) of the fonts. This is to ensure the + quality of the fonts, both to protect Bitstream and Gnome. We want to + ensure that if an application has opened a font specifically of these + names, it gets what it expects (though of course, using fontconfig, + substitutions could still could have occurred during font + opening). You must include the Bitstream copyright. Additional + copyrights can be added, as per copyright law. Happy Font Hacking! + + 6. If I have improvements for Bitstream Vera, is it possible they might get + adopted in future versions? + + Yes. The contract between the Gnome Foundation and Bitstream has + provisions for working with Bitstream to ensure quality additions to + the Bitstream Vera font family. Please contact us if you have such + additions. Note, that in general, we will want such additions for the + entire family, not just a single font, and that you'll have to keep + both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add + glyphs to the font, they must be stylistically in keeping with Vera's + design. Vera cannot become a "ransom note" font. Jim Lyles will be + providing a document describing the design elements used in Vera, as a + guide and aid for people interested in contributing to Vera. + + 7. I want to sell a software package that uses these fonts: Can I do so? + + Sure. Bundle the fonts with your software and sell your software + with the fonts. That is the intent of the copyright. + + 8. If applications have built the names "Bitstream Vera" into them, + can I override this somehow to use fonts of my choosing? + + This depends on exact details of the software. Most open source + systems and software (e.g., Gnome, KDE, etc.) are now converting to + use fontconfig (see www.fontconfig.org) to handle font configuration, + selection and substitution; it has provisions for overriding font + names and subsituting alternatives. An example is provided by the + supplied local.conf file, which chooses the family Bitstream Vera for + "sans", "serif" and "monospace". Other software (e.g., the XFree86 + core server) has other mechanisms for font substitution. + diff --git a/fonts/VeraMono.ttf b/fonts/VeraMono.ttf new file mode 100644 index 0000000..139f0b4 Binary files /dev/null and b/fonts/VeraMono.ttf differ diff --git a/images/backdrop.tga b/images/backdrop.tga new file mode 100644 index 0000000..f061cda Binary files /dev/null and b/images/backdrop.tga differ diff --git a/images/borders.tga b/images/borders.tga new file mode 100644 index 0000000..42f9e27 Binary files /dev/null and b/images/borders.tga differ diff --git a/images/editorTab.tga b/images/editorTab.tga new file mode 100644 index 0000000..8a2a865 Binary files /dev/null and b/images/editorTab.tga differ diff --git a/images/footCorner.tga b/images/footCorner.tga new file mode 100644 index 0000000..3780e58 Binary files /dev/null and b/images/footCorner.tga differ diff --git a/images/footer.tga b/images/footer.tga new file mode 100644 index 0000000..0983828 Binary files /dev/null and b/images/footer.tga differ diff --git a/images/headCorner.tga b/images/headCorner.tga new file mode 100644 index 0000000..83b28fc Binary files /dev/null and b/images/headCorner.tga differ diff --git a/images/header.tga b/images/header.tga new file mode 100644 index 0000000..7266823 Binary files /dev/null and b/images/header.tga differ diff --git a/images/icons/close.png b/images/icons/close.png new file mode 100644 index 0000000..7e4fbd5 Binary files /dev/null and b/images/icons/close.png differ diff --git a/images/icons/close.tga b/images/icons/close.tga new file mode 100644 index 0000000..738733e Binary files /dev/null and b/images/icons/close.tga differ diff --git a/images/icons/delete.tga b/images/icons/delete.tga new file mode 100644 index 0000000..1d328e2 Binary files /dev/null and b/images/icons/delete.tga differ diff --git a/images/icons/down-pushed.png b/images/icons/down-pushed.png new file mode 100644 index 0000000..8591a4c Binary files /dev/null and b/images/icons/down-pushed.png differ diff --git a/images/icons/down-pushed.tga b/images/icons/down-pushed.tga new file mode 100644 index 0000000..fbc049c Binary files /dev/null and b/images/icons/down-pushed.tga differ diff --git a/images/icons/down.png b/images/icons/down.png new file mode 100644 index 0000000..d940908 Binary files /dev/null and b/images/icons/down.png differ diff --git a/images/icons/down.tga b/images/icons/down.tga new file mode 100644 index 0000000..715c724 Binary files /dev/null and b/images/icons/down.tga differ diff --git a/images/icons/edit.png b/images/icons/edit.png new file mode 100644 index 0000000..1e24e7c Binary files /dev/null and b/images/icons/edit.png differ diff --git a/images/icons/edit.tga b/images/icons/edit.tga new file mode 100644 index 0000000..f7f96d8 Binary files /dev/null and b/images/icons/edit.tga differ diff --git a/images/icons/highlight.tga b/images/icons/highlight.tga new file mode 100644 index 0000000..d1d16da Binary files /dev/null and b/images/icons/highlight.tga differ diff --git a/images/icons/left-pushed.png b/images/icons/left-pushed.png new file mode 100644 index 0000000..87f1687 Binary files /dev/null and b/images/icons/left-pushed.png differ diff --git a/images/icons/left-pushed.tga b/images/icons/left-pushed.tga new file mode 100644 index 0000000..a134e7c Binary files /dev/null and b/images/icons/left-pushed.tga differ diff --git a/images/icons/left.png b/images/icons/left.png new file mode 100644 index 0000000..81d1c4b Binary files /dev/null and b/images/icons/left.png differ diff --git a/images/icons/left.tga b/images/icons/left.tga new file mode 100644 index 0000000..19655b2 Binary files /dev/null and b/images/icons/left.tga differ diff --git a/images/icons/new.png b/images/icons/new.png new file mode 100644 index 0000000..15b338f Binary files /dev/null and b/images/icons/new.png differ diff --git a/images/icons/new.tga b/images/icons/new.tga new file mode 100644 index 0000000..9ab209f Binary files /dev/null and b/images/icons/new.tga differ diff --git a/images/icons/open.png b/images/icons/open.png new file mode 100644 index 0000000..301c78c Binary files /dev/null and b/images/icons/open.png differ diff --git a/images/icons/open.tga b/images/icons/open.tga new file mode 100644 index 0000000..58df70b Binary files /dev/null and b/images/icons/open.tga differ diff --git a/images/icons/padlock-disabled.png b/images/icons/padlock-disabled.png new file mode 100644 index 0000000..6dc92c2 Binary files /dev/null and b/images/icons/padlock-disabled.png differ diff --git a/images/icons/padlock-disabled.tga b/images/icons/padlock-disabled.tga new file mode 100644 index 0000000..9eefb59 Binary files /dev/null and b/images/icons/padlock-disabled.tga differ diff --git a/images/icons/padlock.png b/images/icons/padlock.png new file mode 100644 index 0000000..a292c62 Binary files /dev/null and b/images/icons/padlock.png differ diff --git a/images/icons/padlock.tga b/images/icons/padlock.tga new file mode 100644 index 0000000..4285728 Binary files /dev/null and b/images/icons/padlock.tga differ diff --git a/images/icons/pin.png b/images/icons/pin.png new file mode 100644 index 0000000..9c431a5 Binary files /dev/null and b/images/icons/pin.png differ diff --git a/images/icons/pin.tga b/images/icons/pin.tga new file mode 100644 index 0000000..82939e4 Binary files /dev/null and b/images/icons/pin.tga differ diff --git a/images/icons/pinned.png b/images/icons/pinned.png new file mode 100644 index 0000000..278c290 Binary files /dev/null and b/images/icons/pinned.png differ diff --git a/images/icons/pinned.tga b/images/icons/pinned.tga new file mode 100644 index 0000000..5e9f6c1 Binary files /dev/null and b/images/icons/pinned.tga differ diff --git a/images/icons/right-pushed.png b/images/icons/right-pushed.png new file mode 100644 index 0000000..c7db962 Binary files /dev/null and b/images/icons/right-pushed.png differ diff --git a/images/icons/right-pushed.tga b/images/icons/right-pushed.tga new file mode 100644 index 0000000..dac6704 Binary files /dev/null and b/images/icons/right-pushed.tga differ diff --git a/images/icons/right.png b/images/icons/right.png new file mode 100644 index 0000000..d07e88c Binary files /dev/null and b/images/icons/right.png differ diff --git a/images/icons/right.tga b/images/icons/right.tga new file mode 100644 index 0000000..5a667e6 Binary files /dev/null and b/images/icons/right.tga differ diff --git a/images/icons/run-1.tga b/images/icons/run-1.tga new file mode 100644 index 0000000..2dc8229 Binary files /dev/null and b/images/icons/run-1.tga differ diff --git a/images/icons/run.tga b/images/icons/run.tga new file mode 100644 index 0000000..299dcd0 Binary files /dev/null and b/images/icons/run.tga differ diff --git a/images/icons/save.png b/images/icons/save.png new file mode 100644 index 0000000..978163f Binary files /dev/null and b/images/icons/save.png differ diff --git a/images/icons/save.tga b/images/icons/save.tga new file mode 100644 index 0000000..b673b7a Binary files /dev/null and b/images/icons/save.tga differ diff --git a/images/icons/undo.png b/images/icons/undo.png new file mode 100644 index 0000000..0e9a1af Binary files /dev/null and b/images/icons/undo.png differ diff --git a/images/icons/undo.tga b/images/icons/undo.tga new file mode 100644 index 0000000..2bcee98 Binary files /dev/null and b/images/icons/undo.tga differ diff --git a/images/icons/up-pushed.png b/images/icons/up-pushed.png new file mode 100644 index 0000000..982ad94 Binary files /dev/null and b/images/icons/up-pushed.png differ diff --git a/images/icons/up-pushed.tga b/images/icons/up-pushed.tga new file mode 100644 index 0000000..c5f1bc1 Binary files /dev/null and b/images/icons/up-pushed.tga differ diff --git a/images/icons/up.png b/images/icons/up.png new file mode 100644 index 0000000..ca948e7 Binary files /dev/null and b/images/icons/up.png differ diff --git a/images/icons/up.tga b/images/icons/up.tga new file mode 100644 index 0000000..c1f4e51 Binary files /dev/null and b/images/icons/up.tga differ