Mercurial > wow > reaction
diff libs/AceConsole-2.0/AceConsole-2.0.lua @ 1:c11ca1d8ed91
Version 0.1
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Tue, 20 Mar 2007 21:03:57 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/AceConsole-2.0/AceConsole-2.0.lua Tue Mar 20 21:03:57 2007 +0000 @@ -0,0 +1,2058 @@ +--[[ +Name: AceConsole-2.0 +Revision: $Rev: 19865 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceConsole-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceConsole-2.0 +Description: Mixin to allow for input/output capabilities. This uses the + AceOptions data table format to determine input. + http://wiki.wowace.com/index.php/AceOptions_data_table +Dependencies: AceLibrary, AceOO-2.0 +]] + +local MAJOR_VERSION = "AceConsole-2.0" +local MINOR_VERSION = "$Revision: 19865 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end + +local MAP_ONOFF, USAGE, IS_CURRENTLY_SET_TO, IS_NOW_SET_TO, IS_NOT_A_VALID_OPTION_FOR, IS_NOT_A_VALID_VALUE_FOR, NO_OPTIONS_AVAILABLE, OPTION_HANDLER_NOT_FOUND, OPTION_HANDLER_NOT_VALID, OPTION_IS_DISABLED, KEYBINDING_USAGE +if GetLocale() == "deDE" then + MAP_ONOFF = { [false] = "|cffff0000Aus|r", [true] = "|cff00ff00An|r" } + USAGE = "Benutzung" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r steht momentan auf |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r ist nun auf |cffffff7f[|r%s|cffffff7f]|r gesetzt" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] ist keine g\195\188ltige Option f\195\188r |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] ist kein g\195\188ltiger Wert f\195\188r |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "Keine Optionen verfügbar" + OPTION_HANDLER_NOT_FOUND = "Optionen handler |cffffff7f%q|r nicht gefunden." + OPTION_HANDLER_NOT_VALID = "Optionen handler nicht g\195\188ltig." + OPTION_IS_DISABLED = "Option |cffffff7f%s|r deaktiviert." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix +elseif GetLocale() == "frFR" then + MAP_ONOFF = { [false] = "|cffff0000Inactif|r", [true] = "|cff00ff00Actif|r" } + USAGE = "Utilisation" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est actuellement positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r est maintenant positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] n'est pas une option valide pour |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] n'est pas une valeur valide pour |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "Pas d'options disponibles" + OPTION_HANDLER_NOT_FOUND = "Le gestionnaire d'option |cffffff7f%q|r n'a pas \195\169t\195\169 trouv\195\169." + OPTION_HANDLER_NOT_VALID = "Le gestionnaire d'option n'est pas valide." + OPTION_IS_DISABLED = "L'option |cffffff7f%s|r est d\195\169sactiv\195\169e." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix +elseif GetLocale() == "koKR" then + MAP_ONOFF = { [false] = "|cffff0000끔|r", [true] = "|cff00ff00켬|r" } + USAGE = "사용법" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r|1은;는; 현재 상태는 |cffffff7f[|r%s|cffffff7f]|r|1으로;로; 설정되어 있습니다" + IS_NOW_SET_TO = "|cffffff7f%s|r|1을;를; |cffffff7f[|r%s|cffffff7f]|r 상태로 변경합니다" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용불가능한 설정입니다" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용불가능한 설정값입니다" + NO_OPTIONS_AVAILABLE = "가능한 설정이 없습니다" + OPTION_HANDLER_NOT_FOUND = "설정 조정값인 |cffffff7f%q|r|1을;를; 찾지 못했습니다." + OPTION_HANDLER_NOT_VALID = "설정 조정값이 올바르지 않습니다." + OPTION_IS_DISABLED = "|cffffff7f%s|r 설정은 사용할 수 없습니다." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix +elseif GetLocale() == "zhCN" then + MAP_ONOFF = { [false] = "|cffff0000\229\133\179\233\151\173|r", [true] = "|cff00ff00\229\188\128\229\144\175|r" } + USAGE = "\231\148\168\230\179\149" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r \229\189\147\229\137\141\232\162\171\232\174\190\231\189\174 |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r \231\142\176\229\156\168\232\162\171\232\174\190\231\189\174\228\184\186 |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\231\154\132\233\128\137\233\161\185 \228\184\186 |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\229\128\188 \228\184\186 |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "\230\178\161\230\156\137\233\128\137\233\161\185\229\143\175\231\148\168" + OPTION_HANDLER_NOT_FOUND = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 |cffffff7f%q|r \230\178\161\230\159\165\230\137\190." + OPTION_HANDLER_NOT_VALID = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 \230\151\160\230\149\136." + OPTION_IS_DISABLED = "\233\128\137\233\161\185 |cffffff7f%s|r \228\184\141\229\174\140\230\149\180." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix +elseif GetLocale() == "zhTW" then + MAP_ONOFF = { [false] = "|cffff0000關閉|r", [true] = "|cff00ff00開啟|r" } + USAGE = "用法" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r 目前的設定為 |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r 現在被設定為 |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] 是一個不符合規定的選項,對 |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] 是一個不符合規定的數值,對 |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "沒有可用的選項處理器。" + OPTION_HANDLER_NOT_FOUND = "找不到 |cffffff7f%q|r 選項處理器。" + OPTION_HANDLER_NOT_VALID = "選項處理器不符合規定。" + OPTION_IS_DISABLED = "|cffffff7f%s|r 已被停用。" + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix +else -- enUS + MAP_ONOFF = { [false] = "|cffff0000Off|r", [true] = "|cff00ff00On|r" } + USAGE = "Usage" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r is currently set to |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r is now set to |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] is not a valid option for |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] is not a valid value for |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "No options available" + OPTION_HANDLER_NOT_FOUND = "Option handler |cffffff7f%q|r not found." + OPTION_HANDLER_NOT_VALID = "Option handler not valid." + OPTION_IS_DISABLED = "Option |cffffff7f%s|r is disabled." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" +end + +local NONE = NONE or "None" + +local AceOO = AceLibrary("AceOO-2.0") +local AceEvent + +local AceConsole = AceOO.Mixin { "Print", "PrintComma", "CustomPrint", "RegisterChatCommand" } +local Dewdrop + +local _G = getfenv(0) + +local function print(text, name, r, g, b, frame, delay) + if not text or text:len() == 0 then + text = " " + end + if not name or name == AceConsole then + (frame or DEFAULT_CHAT_FRAME):AddMessage(text, r, g, b, nil, delay or 5) + else + (frame or DEFAULT_CHAT_FRAME):AddMessage("|cffffff78" .. tostring(name) .. ":|r " .. text, r, g, b, nil, delay or 5) + end +end + +local real_tostring = tostring + +local function tostring(t) + if type(t) == "table" then + if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then + return string.format("<%s:%s>", t:GetObjectType(), t:GetName() or "(anon)") + end + end + return real_tostring(t) +end + +local function _tostring(...) + if select('#', ...) < 1 then + return + end + return tostring((...)), _tostring(select(2, ...)) +end +function AceConsole:CustomPrint(r, g, b, frame, delay, connector, a1, ...) + if tostring(a1):find("%%") and select('#', ...) >= 1 then + local success, text = pcall(string.format, _tostring(a1, ...)) + if success then + print(text, self, r, g, b, frame or self.printFrame, delay) + return + end + end + print((connector or " "):join(_tostring(a1, ...)), self, r, g, b, frame or self.printFrame, delay) +end + +function AceConsole:Print(...) + return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, " ", ...) +end + +function AceConsole:PrintComma(...) + return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, ", ", ...) +end + +local work +local argwork + +local function findTableLevel(self, options, chat, text, index, passTable) + if not index then + index = 1 + if work then + for k,v in pairs(work) do + work[k] = nil + end + for k,v in pairs(argwork) do + argwork[k] = nil + end + else + work = {} + argwork = {} + end + local len = text:len() + local count + repeat + text, count = text:gsub("(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[[^%]]-) (.-%]|h|r)", "%1\001%2") + until count == 0 + text = text:gsub("(%]|h|r)(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[)", "%1 %2") + for token in text:gmatch("([^%s]+)") do + local token = token + local num = tonumber(token) + if num then + token = num + else + token = token:gsub("\001", " ") + end + table.insert(work, token) + end + end + + local path = chat + for i = 1, index - 1 do + path = path .. " " .. tostring(work[i]) + end + + if type(options.args) == "table" then + local disabled, hidden = options.disabled, options.cmdHidden or options.hidden + if hidden then + if type(hidden) == "function" then + hidden = hidden() + elseif type(hidden) == "string" then + local handler = options.handler or self + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + hidden = handler[f](handler) + if neg then + hidden = not hidden + end + end + end + if hidden then + disabled = true + elseif disabled then + if type(disabled) == "function" then + disabled = disabled() + elseif type(disabled) == "string" then + local handler = options.handler or self + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + disabled = handler[f](handler) + if neg then + disabled = not disabled + end + end + end + if not disabled then + local next = work[index] and work[index]:lower() + if next then + for k,v in pairs(options.args) do + local good = false + if k:lower() == next then + good = true + elseif type(v.aliases) == "table" then + for _,alias in ipairs(v.aliases) do + if alias:lower() == next then + good = true + break + end + end + elseif type(v.aliases) == "string" and v.aliases:lower() == next then + good = true + end + if good then + return findTableLevel(options.handler or self, v, chat, text, index + 1, options.pass and options or nil) + end + end + end + end + end + for i = index, #work do + table.insert(argwork, work[i]) + end + return options, path, argwork, options.handler or self, passTable, passTable and work[index - 1] +end + +local function validateOptionsMethods(self, options, position) + if type(options) ~= "table" then + return "Options must be a table.", position + end + self = options.handler or self + if options.type == "execute" then + if options.func and type(options.func) ~= "string" and type(options.func) ~= "function" then + return "func must be a string or function", position + end + if options.func and type(options.func) == "string" and type(self[options.func]) ~= "function" then + return string.format("%q is not a proper function", options.func), position + end + else + if options.get then + if type(options.get) ~= "string" and type(options.get) ~= "function" then + return "get must be a string or function", position + end + if type(options.get) == "string" then + local f = options.get + if options.type == "toggle" then + f = f:match("^~(.-)$") or f + end + if type(self[f]) ~= "function" then + return string.format("%q is not a proper function", f), position + end + end + end + if options.set then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return "set must be a string or function", position + end + if type(options.set) == "string" and type(self[options.set]) ~= "function" then + return string.format("%q is not a proper function", options.set), position + end + end + if options.validate and type(options.validate) ~= "table" and options.validate ~= "keybinding" then + if type(options.validate) ~= "string" and type(options.validate) ~= "function" then + return "validate must be a string or function", position + end + if type(options.validate) == "string" and type(self[options.validate]) ~= "function" then + return string.format("%q is not a proper function", options.validate), position + end + end + end + if options.disabled and type(options.disabled) == "string" then + local f = options.disabled + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return string.format("%q is not a proper function", f), position + end + end + if options.cmdHidden and type(options.cmdHidden) == "string" then + local f = options.cmdHidden + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return string.format("%q is not a proper function", f), position + end + end + if options.guiHidden and type(options.guiHidden) == "string" then + local f = options.guiHidden + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return string.format("%q is not a proper function", f), position + end + end + if options.hidden and type(options.hidden) == "string" then + local f = options.hidden + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return string.format("%q is not a proper function", f), position + end + end + if options.type == "group" and type(options.args) == "table" then + for k,v in pairs(options.args) do + if type(v) == "table" then + local newposition + if position then + newposition = position .. ".args." .. k + else + newposition = "args." .. k + end + local err, pos = validateOptionsMethods(self, v, newposition) + if err then + return err, pos + end + end + end + end +end + +local function validateOptions(options, position, baseOptions, fromPass) + if not baseOptions then + baseOptions = options + end + if type(options) ~= "table" then + return "Options must be a table.", position + end + local kind = options.type + if type(kind) ~= "string" then + return '"type" must be a string.', position + elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then + return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position + end + if options.aliases then + if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then + return '"alias" must be a table or string', position + end + end + if not fromPass then + if kind == "execute" then + if type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + elseif kind == "range" or kind == "text" or kind == "toggle" then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if kind == "text" and options.get == false then + elseif type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif kind == "group" and options.pass then + if options.pass ~= true then + return '"pass" must be either nil, true, or false', position + end + if not options.func then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + end + else + if kind == "group" then + return 'cannot have "type" = "group" as a subgroup of a passing group', position + end + end + if options ~= baseOptions then + if kind == "header" then + elseif type(options.desc) ~= "string" then + return '"desc" must be a string', position + elseif options.desc:len() == 0 then + return '"desc" cannot be a 0-length string', position + end + end + + if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then + if options.type == "header" and not options.cmdName and not options.name then + elseif options.cmdName then + if type(options.cmdName) ~= "string" then + return '"cmdName" must be a string or nil', position + elseif options.cmdName:len() == 0 then + return '"cmdName" cannot be a 0-length string', position + end + if type(options.guiName) ~= "string" then + if not options.guiNameIsMap then + return '"guiName" must be a string or nil', position + end + elseif options.guiName:len() == 0 then + return '"guiName" cannot be a 0-length string', position + end + else + if type(options.name) ~= "string" then + return '"name" must be a string', position + elseif options.name:len() == 0 then + return '"name" cannot be a 0-length string', position + end + end + end + if options.guiNameIsMap then + if type(options.guiNameIsMap) ~= "boolean" then + return '"guiNameIsMap" must be a boolean or nil', position + elseif options.type ~= "toggle" then + return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position + elseif type(options.map) ~= "table" then + return '"map" must be a table', position + end + end + if options.message and type(options.message) ~= "string" then + return '"message" must be a string or nil', position + end + if options.error and type(options.error) ~= "string" then + return '"error" must be a string or nil', position + end + if options.current and type(options.current) ~= "string" then + return '"current" must be a string or nil', position + end + if options.order then + if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then + return '"order" must be a non-zero number or nil', position + end + end + if options.disabled then + if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then + return '"disabled" must be a function, string, or boolean', position + end + end + if options.cmdHidden then + if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then + return '"cmdHidden" must be a function, string, or boolean', position + end + end + if options.guiHidden then + if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then + return '"guiHidden" must be a function, string, or boolean', position + end + end + if options.hidden then + if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then + return '"hidden" must be a function, string, or boolean', position + end + end + if kind == "text" then + if type(options.validate) == "table" then + local t = options.validate + local iTable = nil + for k,v in pairs(t) do + if type(k) == "number" then + if iTable == nil then + iTable = true + elseif not iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + elseif k < 1 or k > #t then + return '"validate" numeric keys must be indexed properly. >= 1 and <= #validate', position + end + else + if iTable == nil then + iTable = false + elseif iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + end + end + if type(v) ~= "string" then + return '"validate" values must all be strings', position + end + end + elseif options.validate == "keybinding" then + + else + if type(options.usage) ~= "string" then + return '"usage" must be a string', position + elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then + return '"validate" must be a string, function, or table', position + end + end + elseif kind == "range" then + if options.min or options.max then + if type(options.min) ~= "number" then + return '"min" must be a number', position + elseif type(options.max) ~= "number" then + return '"max" must be a number', position + elseif options.min >= options.max then + return '"min" must be less than "max"', position + end + end + if options.step then + if type(options.step) ~= "number" then + return '"step" must be a number', position + elseif options.step < 0 then + return '"step" must be nonnegative', position + end + end + if options.isPercent and options.isPercent ~= true then + return '"isPercent" must either be nil, true, or false', position + end + elseif kind == "toggle" then + if options.map then + if type(options.map) ~= "table" then + return '"map" must be a table', position + elseif type(options.map[true]) ~= "string" then + return '"map[true]" must be a string', position + elseif type(options.map[false]) ~= "string" then + return '"map[false]" must be a string', position + end + end + elseif kind == "color" then + if options.hasAlpha and options.hasAlpha ~= true then + return '"hasAlpha" must be nil, true, or false', position + end + elseif kind == "group" then + if options.pass and options.pass ~= true then + return '"pass" must be nil, true, or false', position + end + if type(options.args) ~= "table" then + return '"args" must be a table', position + end + for k,v in pairs(options.args) do + if type(k) ~= "string" then + return '"args" keys must be strings', position + elseif k:find("%s") then + return string.format('"args" keys must not include spaces. %q is not appropriate.', k), position + elseif k:len() == 0 then + return '"args" keys must not be 0-length strings.', position + end + if type(v) ~= "table" then + return '"args" values must be tables', position and position .. "." .. k or k + end + local newposition + if position then + newposition = position .. ".args." .. k + else + newposition = "args." .. k + end + local err, pos = validateOptions(v, newposition, baseOptions, options.pass) + if err then + return err, pos + end + end + end +end + +local colorTable +local colorFunc +local colorCancelFunc + +local function keybindingValidateFunc(text) + if text == nil or text == "NONE" then + return nil + end + text = text:upper() + local shift, ctrl, alt + local modifier + while true do + if text == "-" then + break + end + modifier, text = strsplit('-', text, 2) + if text then + if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then + return false + end + if modifier == "SHIFT" then + if shift then + return false + end + shift = true + end + if modifier == "CTRL" then + if ctrl then + return false + end + ctrl = true + end + if modifier == "ALT" then + if alt then + return false + end + alt = true + end + else + text = modifier + break + end + end + if not text:find("^F%d+$") and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then + return false + end + local s = text + if shift then + s = "SHIFT-" .. s + end + if ctrl then + s = "CTRL-" .. s + end + if alt then + s = "ALT-" .. s + end + return s +end +AceConsole.keybindingValidateFunc = keybindingValidateFunc + +local order + +local mysort_args +local mysort + +local function printUsage(self, handler, realOptions, options, path, args, quiet, filter) + if filter then + filter = "^" .. filter:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + end + local hidden, disabled = options.cmdHidden or options.hidden, options.disabled + if hidden then + if type(hidden) == "function" then + hidden = hidden() + elseif type(hidden) == "string" then + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + hidden = handler[f](handler) + if neg then + hidden = not hidden + end + end + end + if hidden then + disabled = true + elseif disabled then + if type(disabled) == "function" then + disabled = disabled() + elseif type(disabled) == "string" then + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + disabled = handler[f](handler) + if neg then + disabled = not disabled + end + end + end + local kind = (options.type or "group"):lower() + if disabled then + print(string.format(OPTION_IS_DISABLED, path), realOptions.cmdName or realOptions.name or self) + elseif kind == "text" then + local var + if passTable then + if not passTable.get then + elseif type(passTable.get) == "function" then + var = passTable.get(passValue) + else + local handler = passTable.handler or handler + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + var = handler[passTable.get](handler, passValue) + end + else + if not options.get then + elseif type(options.get) == "function" then + var = options.get() + else + local handler = options.handler or handler + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + var = handler[options.get](handler) + end + end + + local usage + if type(options.validate) == "table" then + if filter then + if not order then + order = {} + end + for k,v in pairs(options.validate) do + if v:find(filter) then + table.insert(order, v) + end + end + usage = "{" .. table.concat(order, " || ") .. "}" + for k in pairs(order) do + order[k] = nil + end + else + if not order then + order = {} + end + for k,v in pairs(options.validate) do + table.insert(order, v) + end + usage = "{" .. table.concat(order, " || ") .. "}" + for k in pairs(order) do + order[k] = nil + end + end + var = options.validate[var] or var + elseif options.validate == "keybinding" then + usage = KEYBINDING_USAGE + else + usage = options.usage or "<value>" + end + if not quiet then + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage), realOptions.cmdName or realOptions.name or self) + end + if (passTable and passTable.get) or options.get then + print(string.format(options.current or IS_CURRENTLY_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE))) + end + elseif kind == "range" then + local var + if passTable then + if type(passTable.get) == "function" then + var = passTable.get(passValue) + else + local handler = passTable.handler or handler + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + var = handler[passTable.get](handler, passValue) + end + else + if type(options.get) == "function" then + var = options.get() + else + local handler = options.handler or handler + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + var = handler[options.get](handler) + end + end + + local usage + local min = options.min or 0 + local max = options.max or 1 + if options.isPercent then + min, max = min * 100, max * 100 + var = tostring(var * 100) .. "%" + end + local bit = "-" + if min < 0 or max < 0 then + bit = " - " + end + usage = string.format("(%s%s%s)", min, bit, max) + if not quiet then + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage), realOptions.cmdName or realOptions.name or self) + end + print(string.format(options.current or IS_CURRENTLY_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE))) + elseif kind == "group" then + local usage + if next(options.args) then + if not order then + order = {} + end + for k,v in pairs(options.args) do + if v.type ~= "header" then + local hidden = v.cmdHidden or v.hidden + if hidden then + if type(hidden) == "function" then + hidden = hidden() + elseif type(hidden) == "string" then + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + hidden = handler[f](handler) + if neg then + hidden = not hidden + end + end + end + if not hidden then + if filter then + if k:find(filter) then + table.insert(order, k) + elseif type(v.aliases) == "table" then + for _,bit in ipairs(v.aliases) do + if bit:find(filter) then + table.insert(order, k) + break + end + end + elseif type(v.aliases) == "string" then + if v.aliases:find(filter) then + table.insert(order, k) + end + end + else + table.insert(order, k) + end + end + end + end + if not mysort then + mysort = function(a, b) + local alpha, bravo = mysort_args[a], mysort_args[b] + local alpha_order = alpha and alpha.order or 100 + local bravo_order = bravo and bravo.order or 100 + if alpha_order == bravo_order then + return tostring(a) < tostring(b) + else + if alpha_order < 0 then + if bravo_order > 0 then + return false + end + else + if bravo_order < 0 then + return true + end + end + if alpha_order > 0 and bravo_order > 0 then + return tostring(a) < tostring(b) + end + return alpha_order < bravo_order + end + end + end + mysort_args = options.args + table.sort(order, mysort) + mysort_args = nil + if not quiet then + if options == realOptions then + if options.desc then + print(tostring(options.desc), realOptions.cmdName or realOptions.name or self) + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}")) + elseif self.description or self.notes then + print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}")) + else + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) + end + else + if options.desc then + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) + print(tostring(options.desc)) + else + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) + end + end + end + for _,k in ipairs(order) do + local v = options.args[k] + if v then + local disabled = v.disabled + if disabled then + if type(disabled) == "function" then + disabled = disabled() + elseif type(disabled) == "string" then + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + disabled = handler[f](handler) + if neg then + disabled = not disabled + end + end + end + if type(v.aliases) == "table" then + k = k .. " || " .. table.concat(v.aliases, " || ") + elseif type(v.aliases) == "string" then + k = k .. " || " .. v.aliases + end + if v.get then + local a1,a2,a3,a4 + if type(v.get) == "function" then + if options.pass then + a1,a2,a3,a4 = v.get(k) + else + a1,a2,a3,a4 = v.get() + end + else + local handler = v.handler or handler + local f = v.get + local neg + if v.type == "toggle" then + neg = f:match("^~(.-)$") + if neg then + f = neg + end + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + if options.pass then + a1,a2,a3,a4 = handler[f](handler, k) + else + a1,a2,a3,a4 = handler[f](handler) + end + if neg then + a1 = not a1 + end + end + if v.type == "color" then + if v.hasAlpha then + if not a1 or not a2 or not a3 or not a4 then + s = NONE + else + s = string.format("|c%02x%02x%02x%02x%02x%02x%02x%02x|r", a4*255, a1*255, a2*255, a3*255, a4*255, a1*255, a2*255, a3*255) + end + else + if not a1 or not a2 or not a3 then + s = NONE + else + s = string.format("|cff%02x%02x%02x%02x%02x%02x|r", a1*255, a2*255, a3*255, a1*255, a2*255, a3*255) + end + end + elseif v.type == "toggle" then + if v.map then + s = tostring(v.map[a1 and true or false] or NONE) + else + s = tostring(MAP_ONOFF[a1 and true or false] or NONE) + end + elseif v.type == "range" then + if v.isPercent then + s = tostring(a1 * 100) .. "%" + else + s = tostring(a1) + end + elseif v.type == "text" and type(v.validate) == "table" then + s = tostring(v.validate[a1] or a1 or NONE) + else + s = tostring(a1 or NONE) + end + if disabled then + local s = s:gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") + local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") + print(string.format("|cffcfcfcf - %s: [%s] %s|r", k, s, desc)) + else + print(string.format(" - |cffffff7f%s: [|r%s|cffffff7f]|r %s", k, s, v.desc or NONE)) + end + else + if disabled then + local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") + print(string.format("|cffcfcfcf - %s: %s", k, desc)) + else + print(string.format(" - |cffffff7f%s:|r %s", k, v.desc or NONE)) + end + end + end + end + for k in pairs(order) do + order[k] = nil + end + else + if options.desc then + desc = options.desc + print(string.format("|cffffff7f%s:|r %s", USAGE, path), realOptions.cmdName or realOptions.name or self) + print(tostring(options.desc)) + elseif options == realOptions and (self.description or self.notes) then + print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) + print(string.format("|cffffff7f%s:|r %s", USAGE, path)) + else + print(string.format("|cffffff7f%s:|r %s", USAGE, path), realOptions.cmdName or realOptions.name or self) + end + print(NO_OPTIONS_AVAILABLE) + end + end +end + +local function handlerFunc(self, chat, msg, options) + if not msg then + msg = "" + else + msg = msg:gsub("^%s*(.-)%s*$", "%1") + msg = msg:gsub("%s+", " ") + end + + local realOptions = options + local options, path, args, handler, passTable, passValue = findTableLevel(self, options, chat, msg) + + local hidden, disabled = options.cmdHidden or options.hidden, options.disabled + if hidden then + if type(hidden) == "function" then + hidden = hidden() + elseif type(hidden) == "string" then + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + hidden = handler[f](handler) + if neg then + hidden = not hidden + end + end + end + if hidden then + disabled = true + elseif disabled then + if type(disabled) == "function" then + disabled = disabled() + elseif type(disabled) == "string" then + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + disabled = handler[f](handler) + if neg then + disabled = not disabled + end + end + end + local _G_this = this + local kind = (options.type or "group"):lower() + if disabled then + print(string.format(OPTION_IS_DISABLED, path), realOptions.cmdName or realOptions.name or self) + elseif kind == "text" then + if #args > 0 then + if (type(options.validate) == "table" and #args > 1) or (type(options.validate) ~= "table" and not options.input) then + local arg = table.concat(args, " ") + for k,v in pairs(args) do + args[k] = nil + end + args[1] = arg + end + if options.validate then + local good + if type(options.validate) == "function" then + good = options.validate(unpack(args)) + elseif type(options.validate) == "table" then + local arg = args[1] + arg = tostring(arg):lower() + for k,v in pairs(options.validate) do + if v:lower() == arg then + args[1] = type(k) == "string" and k or v + good = true + break + end + end + if not good and type((next(options.validate))) == "string" then + for k,v in pairs(options.validate) do + if type(k) == "string" and k:lower() == arg then + args[1] = k + good = true + break + end + end + end + elseif options.validate == "keybinding" then + good = keybindingValidateFunc(unpack(args)) + if good ~= false then + args[1] = good + end + else + if type(handler[options.validate]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.validate)) + end + good = handler[options.validate](handler, unpack(args)) + end + if not good then + local usage + if type(options.validate) == "table" then + if not order then + order = {} + end + for k,v in pairs(options.validate) do + table.insert(order, v) + end + usage = "{" .. table.concat(order, " || ") .. "}" + for k in pairs(order) do + order[k] = nil + end + elseif options.validate == "keybinding" then + usage = KEYBINDING_USAGE + else + usage = options.usage or "<value>" + end + print(string.format(options.error or IS_NOT_A_VALID_OPTION_FOR, tostring(table.concat(args, " ")), path), realOptions.cmdName or realOptions.name or self) + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage)) + return + end + end + + local var + if passTable then + if not passTable.get then + elseif type(passTable.get) == "function" then + var = passTable.get(passValue) + else + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + var = handler[passTable.get](handler, passValue) + end + else + if not options.get then + elseif type(options.get) == "function" then + var = options.get() + else + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + var = handler[options.get](handler) + end + end + + if var ~= args[1] then + if passTable then + if type(passTable.set) == "function" then + passTable.set(passValue, unpack(args)) + else + if type(handler[passTable.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) + end + handler[passTable.set](handler, passTable.set, unpack(args)) + end + else + if type(options.set) == "function" then + options.set(unpack(args)) + else + if type(handler[options.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) + end + handler[options.set](handler, unpack(args)) + end + end + end + end + + if #args > 0 then + local var + if passTable then + if not passTable.get then + elseif type(passTable.get) == "function" then + var = passTable.get(passValue) + else + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + var = handler[passTable.get](handler, passValue) + end + else + if not options.get then + elseif type(options.get) == "function" then + var = options.get() + else + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + var = handler[options.get](handler) + end + end + if type(options.validate) == "table" then + var = options.validate[var] or var + end + if (passTable and passTable.get) or options.get then + print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) + end + if var == args[1] then + return + end + else + printUsage(self, handler, realOptions, options, path, args) + return + end + elseif kind == "execute" then + if passTable then + if type(passFunc) == "function" then + set(passValue) + else + if type(handler[passFunc]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passFunc)) + end + handler[passFunc](handler, passValue) + end + else + local ret, msg + if type(options.func) == "function" then + options.func() + else + local handler = options.handler or self + if type(handler[options.func]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.func)) + end + handler[options.func](handler) + end + end + elseif kind == "toggle" then + local var + if passTable then + if type(passTable.get) == "function" then + var = passTable.get(passValue) + else + local f = passTable.get + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + var = handler[f](handler, passValue) + if neg then + var = not var + end + end + if type(passTable.set) == "function" then + passTable.set(passValue, not var) + else + if type(handler[passTable.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) + end + handler[passTable.set](handler, passValue, not var) + end + if type(passTable.get) == "function" then + var = passTable.get(passValue) + else + local f = passTable.get + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + var = handler[f](handler, passValue) + if neg then + var = not var + end + end + else + local handler = options.handler or self + if type(options.get) == "function" then + var = options.get() + else + local f = options.get + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) + end + var = handler[f](handler) + if neg then + var = not var + end + end + if type(options.set) == "function" then + options.set(not var) + else + if type(handler[options.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) + end + handler[options.set](handler, not var) + end + if type(options.get) == "function" then + var = options.get() + else + local f = options.get + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + var = handler[f](handler) + if neg then + var = not var + end + end + end + + print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), (options.map or MAP_ONOFF)[var and true or false] or NONE), realOptions.cmdName or realOptions.name or self) + elseif kind == "range" then + local arg + if #args <= 1 then + arg = args[1] + else + arg = table.concat(args, " ") + end + + if arg then + local min = options.min or 0 + local max = options.max or 1 + local good = false + if type(arg) == "number" then + if options.isPercent then + arg = arg / 100 + end + + if arg >= min and arg <= max then + good = true + end + + if good and type(options.step) == "number" and options.step > 0 then + local step = options.step + arg = math.floor((arg - min) / step + 0.5) * step + min + if arg > max then + arg = max + elseif arg < min then + arg = min + end + end + end + if not good then + local usage + local min = options.min or 0 + local max = options.max or 1 + if options.isPercent then + min, max = min * 100, max * 100 + end + local bit = "-" + if min < 0 or max < 0 then + bit = " - " + end + usage = string.format("(%s%s%s)", min, bit, max) + print(string.format(options.error or IS_NOT_A_VALID_VALUE_FOR, tostring(arg), path), realOptions.cmdName or realOptions.name or self) + print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage)) + return + end + + local var + if passTable then + if type(passTable.get) == "function" then + var = passTable.get(passValue) + else + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + var = handler[passTable.get](handler, passValue) + end + else + if type(options.get) == "function" then + var = options.get() + else + local handler = options.handler or self + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + var = handler[options.get](handler) + end + end + + if var ~= arg then + if passTable then + if type(passTable.set) == "function" then + passTable.set(passValue, arg) + else + if type(handler[passTable.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) + end + handler[passTable.set](handler, passValue, arg) + end + else + if type(options.set) == "function" then + options.set(arg) + else + local handler = options.handler or self + if type(handler[options.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) + end + handler[options.set](handler, arg) + end + end + end + end + + if arg then + local var + if passTable then + if type(passTable.get) == "function" then + var = passTable.get(passValue) + else + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + var = handler[passTable.get](handler, passValue) + end + else + if type(options.get) == "function" then + var = options.get() + else + local handler = options.handler or self + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + var = handler[options.get](handler) + end + end + + if var and options.isPercent then + var = tostring(var * 100) .. "%" + end + print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) + if var == arg then + return + end + else + printUsage(self, handler, realOptions, options, path, args) + return + end + elseif kind == "color" then + if #args > 0 then + local r,g,b,a + if #args == 1 then + local arg = tostring(args[1]) + if options.hasAlpha then + if arg:len() == 8 and arg:find("^%x*$") then + r,g,b,a = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255, tonumber(arg:sub(7, 8), 16) / 255 + end + else + if arg:len() == 6 and arg:find("^%x*$") then + r,g,b = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255 + end + end + elseif #args == 4 and options.hasAlpha then + local a1,a2,a3,a4 = args[1], args[2], args[3], args[4] + if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and type(a4) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 and a4 <= 1 then + r,g,b,a = a1,a2,a3,a4 + elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") and (type(a4) == "number" or a4:len() == 2) and a4:find("^%x*$") then + r,g,b,a = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255, tonumber(a4, 16) / 255 + end + elseif #args == 3 and not options.hasAlpha then + local a1,a2,a3 = args[1], args[2], args[3] + if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 then + r,g,b = a1,a2,a3 + elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") then + r,g,b = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255 + end + end + if not r then + print(string.format(options.error or IS_NOT_A_VALID_OPTION_FOR, table.concat(args, ' '), path), realOptions.cmdName or realOptions.name or self) + print(string.format("|cffffff7f%s:|r %s {0-1} {0-1} {0-1}%s", USAGE, path, options.hasAlpha and " {0-1}" or "")) + return + end + if passTable then + if type(passTable.set) == "function" then + passTable.set(passValue, r,g,b,a) + else + if type(handler[passTable.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) + end + handler[passTable.set](handler, passValue, r,g,b,a) + end + else + if type(options.set) == "function" then + options.set(r,g,b,a) + else + if type(handler[options.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) + end + handler[options.set](handler, r,g,b,a) + end + end + + local r,g,b,a + if passTable then + if type(passTable.get) == "function" then + r,g,b,a = passTable.get(passValue) + else + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + r,g,b,a = handler[passTable.get](handler, passValue) + end + else + if type(options.get) == "function" then + r,g,b,a = options.get() + else + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + r,g,b,a = handler[options.get](handler) + end + end + + local s + if type(r) == "number" and type(g) == "number" and type(b) == "number" then + if options.hasAlpha and type(a) == "number" then + s = string.format("|c%02x%02x%02x%02x%02x%02x%02x%02x|r", a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) + else + s = string.format("|cff%02x%02x%02x%02x%02x%02x|r", r*255, g*255, b*255, r*255, g*255, b*255) + end + else + s = NONE + end + print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), s), realOptions.cmdName or realOptions.name or self) + else + local r,g,b,a + if passTable then + if type(passTable.get) == "function" then + r,g,b,a = passTable.get(passValue) + else + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) + end + r,g,b,a = handler[passTable.get](handler, passValue) + end + else + if type(options.get) == "function" then + r,g,b,a = options.get() + else + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) + end + r,g,b,a = handler[options.get](handler) + end + end + + if not colorTable then + colorTable = {} + local t = colorTable + + if ColorPickerOkayButton then + local ColorPickerOkayButton_OnClick = ColorPickerOkayButton:GetScript("OnClick") + ColorPickerOkayButton:SetScript("OnClick", function() + if ColorPickerOkayButton_OnClick then + ColorPickerOkayButton_OnClick() + end + if t.active then + ColorPickerFrame.cancelFunc = nil + ColorPickerFrame.func = nil + ColorPickerFrame.opacityFunc = nil + local r,g,b,a + if t.passValue then + if type(t.get) == "function" then + r,g,b,a = t.get(t.passValue) + else + if type(t.handler[t.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.get)) + end + r,g,b,a = t.handler[t.get](t.handler, t.passValue) + end + else + if type(t.get) == "function" then + r,g,b,a = t.get() + else + if type(t.handler[t.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.get)) + end + r,g,b,a = t.handler[t.get](t.handler) + end + end + if r ~= t.r or g ~= t.g or b ~= t.b or (t.hasAlpha and a ~= t.a) then + local s + if type(r) == "number" and type(g) == "number" and type(b) == "number" then + if t.hasAlpha and type(a) == "number" then + s = string.format("|c%02x%02x%02x%02x%02x%02x%02x%02x|r", a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) + else + s = string.format("|cff%02x%02x%02x%02x%02x%02x|r", r*255, g*255, b*255, r*255, g*255, b*255) + end + else + s = NONE + end + print(string.format(t.message, tostring(t.name), s), t.realOptions.cmdName or t.realOptions.name or self) + end + for k,v in pairs(t) do + t[k] = nil + end + end + end) + end + else + for k,v in pairs(colorTable) do + colorTable[k] = nil + end + end + + if type(r) ~= "number" or type(g) ~= "number" or type(b) ~= "number" then + r,g,b = 1, 1, 1 + end + if type(a) ~= "number" then + a = 1 + end + local t = colorTable + t.r = r + t.g = g + t.b = b + if hasAlpha then + t.a = a + end + t.realOptions = realOptions + t.hasAlpha = options.hasAlpha + t.handler = handler + t.set = passTable and passTable.set or options.set + t.get = passTable and passTable.get or options.get + t.name = options.cmdName or options.name + t.message = options.message or IS_NOW_SET_TO + t.passValue = passValue + t.active = true + + if not colorFunc then + colorFunc = function() + local r,g,b = ColorPickerFrame:GetColorRGB() + if t.hasAlpha then + local a = 1 - OpacitySliderFrame:GetValue() + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, r,g,b,a) + else + t.set(r,g,b,a) + end + else + if type(t.handler[t.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.set)) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, r,g,b,a) + else + t.handler[t.set](t.handler, r,g,b,a) + end + end + else + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, r,g,b) + else + t.set(r,g,b) + end + else + if type(t.handler[t.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.set)) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, r,g,b) + else + t.handler[t.set](t.handler, r,g,b) + end + end + end + end + end + + ColorPickerFrame.func = colorFunc + ColorPickerFrame.hasOpacity = options.hasAlpha + if options.hasAlpha then + ColorPickerFrame.opacityFunc = ColorPickerFrame.func + ColorPickerFrame.opacity = 1 - a + end + ColorPickerFrame:SetColorRGB(r,g,b) + + if not colorCancelFunc then + colorCancelFunc = function() + if t.hasAlpha then + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, t.r,t.g,t.b,t.a) + else + t.set(t.r,t.g,t.b,t.a) + end + else + if type(t.handler[t.get]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.get)) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b,t.a) + else + t.handler[t.set](t.handler, t.r,t.g,t.b,t.a) + end + end + else + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, t.r,t.g,t.b) + else + t.set(t.r,t.g,t.b) + end + else + if type(t.handler[t.set]) ~= "function" then + AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.set)) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b) + else + t.handler[t.set](t.handler, t.r,t.g,t.b) + end + end + end + for k,v in pairs(t) do + t[k] = nil + end + ColorPickerFrame.cancelFunc = nil + ColorPickerFrame.func = nil + ColorPickerFrame.opacityFunc = nil + end + end + + ColorPickerFrame.cancelFunc = colorCancelFunc + + ShowUIPanel(ColorPickerFrame) + end + return + elseif kind == "group" then + if #args == 0 then + printUsage(self, handler, realOptions, options, path, args) + else + -- invalid argument + print(string.format(options.error or IS_NOT_A_VALID_OPTION_FOR, args[1], path), realOptions.cmdName or realOptions.name or self) + end + return + end + this = _G_this + if Dewdrop then + Dewdrop:Refresh(1) + Dewdrop:Refresh(2) + Dewdrop:Refresh(3) + Dewdrop:Refresh(4) + Dewdrop:Refresh(5) + end +end + +local external +function AceConsole:RegisterChatCommand(slashCommands, options, name) + if type(slashCommands) ~= "table" and slashCommands ~= false then + AceConsole:error("Bad argument #2 to `RegisterChatCommand' (expected table, got %s)", type(slashCommands)) + end + if not slashCommands and type(name) ~= "string" then + AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string, got %s)", type(name)) + end + if type(options) ~= "table" and type(options) ~= "function" and options ~= nil then + AceConsole:error("Bad argument #3 to `RegisterChatCommand' (expected table, function, or nil, got %s)", type(options)) + end + if name then + if type(name) ~= "string" then + AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string or nil, got %s)", type(name)) + elseif not name:find("^%w+$") or name:upper() ~= name or name:len() == 0 then + AceConsole:error("Argument #4 must be an uppercase, letters-only string with at least 1 character") + end + end + if slashCommands then + if #slashCommands == 0 then + AceConsole:error("Argument #2 to `RegisterChatCommand' must include at least one string") + end + + for k,v in pairs(slashCommands) do + if type(k) ~= "number" then + AceConsole:error("All keys in argument #2 to `RegisterChatCommand' must be numbers") + end + if type(v) ~= "string" then + AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be strings") + elseif not v:find("^/[A-Za-z][A-Za-z0-9_]*$") then + AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be in the form of \"/word\"") + end + end + end + + if not options then + options = { + type = 'group', + args = {}, + handler = self + } + end + + if type(options) == "table" then + local err, position = validateOptions(options) + if err then + if position then + AceConsole:error(position .. ": " .. err) + else + AceConsole:error(err) + end + end + + if not options.handler then + options.handler = self + end + + if options.handler == self and options.type:lower() == "group" and self.class then + AceConsole:InjectAceOptionsTable(self, options) + end + end + + local chat + if slashCommands then + chat = slashCommands[1] + else + chat = _G["SLASH_"..name..1] + end + + local handler + if type(options) == "function" then + handler = options + for k,v in pairs(_G) do + if handler == v then + local k = k + handler = function(msg) + return _G[k](msg) + end + end + end + else + function handler(msg) + handlerFunc(self, chat, msg, options) + end + end + + if not _G.SlashCmdList then + _G.SlashCmdList = {} + end + + if not name then + local A = ('A'):byte() + repeat + name = string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) + until not _G.SlashCmdList[name] + end + + if slashCommands then + if _G.SlashCmdList[name] then + local i = 0 + while true do + i = i + 1 + if _G["SLASH_"..name..i] then + _G["SLASH_"..name..i] = nil + else + break + end + end + end + + local i = 0 + for _,command in ipairs(slashCommands) do + i = i + 1 + _G["SLASH_"..name..i] = command + if command:lower() ~= command then + i = i + 1 + _G["SLASH_"..name..i] = command:lower() + end + end + end + _G.SlashCmdList[name] = handler + if self ~= AceConsole and self.slashCommand == nil then + self.slashCommand = chat + end + + if not AceEvent and AceLibrary:HasInstance("AceEvent-2.0") then + external(AceConsole, "AceEvent-2.0", AceLibrary("AceEvent-2.0")) + end + if AceEvent then + if not AceConsole.nextAddon then + AceConsole.nextAddon = {} + end + if type(options) == "table" then + AceConsole.nextAddon[self] = options + if not self.playerLogin then + AceConsole:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) + end + end + end + + AceConsole.registry[name] = options +end + +function AceConsole:InjectAceOptionsTable(handler, options) + self:argCheck(handler, 2, "table") + self:argCheck(options, 3, "table") + if options.type:lower() ~= "group" then + self:error('Cannot inject into options table argument #3 if its type is not "group"') + end + if options.handler ~= nil and options.handler ~= handler then + self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") + end + options.handler = handler + local class = handler.class + if not class then + self:error("Cannot retrieve AceOptions tables from a non-object argument #2") + end + while class and class ~= AceOO.Class do + if type(class.GetAceOptionsDataTable) == "function" then + local t = class:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + local mixins = class.mixins + if mixins then + for mixin in pairs(mixins) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + class = class.super + end + return options +end + +function AceConsole:PLAYER_LOGIN() + self.playerLogin = true + for addon, options in pairs(self.nextAddon) do + local err, position = validateOptionsMethods(addon, options) + if err then + if position then + geterrorhandler()(tostring(addon) .. ": AceConsole: " .. position .. ": " .. err) + else + geterrorhandler()(tostring(addon) .. ": AceConsole: " .. err) + end + end + self.nextAddon[addon] = nil + end +end + +function AceConsole:TabCompleteInfo(cmdpath) + local cmd = cmdpath:match("(/%S+)") + if not cmd then + return + end + local path = cmdpath:sub(cmd:len() + 2) + for name in pairs(SlashCmdList) do --global + if AceConsole.registry[name] then + local i = 0 + while true do + i = i + 1 + local scmd = _G["SLASH_"..name..i] + if not scmd then break end + if cmd == scmd then + return name, cmd, path + end + end + end + end +end + +function external(self, major, instance) + if major == "AceEvent-2.0" then + if not AceEvent then + AceEvent = instance + + AceEvent:embed(self) + end + elseif major == "AceTab-2.0" then + instance:RegisterTabCompletion("AceConsole", "%/.*", function(t, cmdpath, pos) + local ac = AceLibrary("AceConsole-2.0") + local name, cmd, path = ac:TabCompleteInfo(cmdpath:sub(1, pos)) + + if not ac.registry[name] then + return false + else + local validArgs = findTableLevel(ac, ac.registry[name], cmd, path or "") + if validArgs.args then + for arg in pairs(validArgs.args) do + table.insert(t, arg) + end + end + end + end, function(u, matches, gcs, cmdpath) + local ac = AceLibrary("AceConsole-2.0") + local name, cmd, path = ac:TabCompleteInfo(cmdpath) + if ac.registry[name] then + local validArgs, path2, argwork = findTableLevel(ac, ac.registry[name], cmd, path) + printUsage(ac, validArgs.handler, ac.registry[name], validArgs, path2, argwork, not gcs or gcs ~= "", gcs) + end + end) + elseif major == "Dewdrop-2.0" then + Dewdrop = instance + end +end + +local function activate(self, oldLib, oldDeactivate) + AceConsole = self + + if oldLib then + self.registry = oldLib.registry + self.nextAddon = oldLib.nextAddon + end + + if not self.registry then + self.registry = {} + else + for name,options in pairs(self.registry) do + self:RegisterChatCommand(false, options, name) + end + end + + self:RegisterChatCommand({ "/reload", "/rl", "/reloadui" }, ReloadUI, "RELOAD") + + self:RegisterChatCommand({ "/print" }, function(text) + local f, err = loadstring("AceLibrary('AceConsole-2.0'):PrintComma(" .. text .. ")") + if not f then + self:Print("|cffff0000Error:|r", err) + else + f() + end + end, "PRINT") + + self:activate(oldLib, oldDeactivate) + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceConsole, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)