annotate Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua @ 8:1b2d819b4fa8

Now using the global MailAddonBusy to indicate MailOpener is busy, read comments in Core.lua for more info. Default status is now ?enabled without automatic mail opening? to let first time users look around before MailOpener messes up their heads. A StaticPopupDialog will be added later to ask if they want to auto-enable. When ?enabled without automatic mail opening? is on and you toggle the mail opening checkbox on, mail opening will automatically start.
author Zerotorescue
date Thu, 09 Sep 2010 10:53:19 +0200
parents 823e33465b6e
children
rev   line source
Zerotorescue@0 1 --- AceConfigCmd-3.0 handles access to an options table through the "command line" interface via the ChatFrames.
Zerotorescue@0 2 -- @class file
Zerotorescue@0 3 -- @name AceConfigCmd-3.0
Zerotorescue@0 4 -- @release $Id: AceConfigCmd-3.0.lua 904 2009-12-13 11:56:37Z nevcairiel $
Zerotorescue@0 5
Zerotorescue@0 6 --[[
Zerotorescue@0 7 AceConfigCmd-3.0
Zerotorescue@0 8
Zerotorescue@0 9 Handles commandline optionstable access
Zerotorescue@0 10
Zerotorescue@0 11 REQUIRES: AceConsole-3.0 for command registration (loaded on demand)
Zerotorescue@0 12
Zerotorescue@0 13 ]]
Zerotorescue@0 14
Zerotorescue@0 15 -- TODO: plugin args
Zerotorescue@0 16
Zerotorescue@0 17
Zerotorescue@0 18 local MAJOR, MINOR = "AceConfigCmd-3.0", 12
Zerotorescue@0 19 local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR)
Zerotorescue@0 20
Zerotorescue@0 21 if not AceConfigCmd then return end
Zerotorescue@0 22
Zerotorescue@0 23 AceConfigCmd.commands = AceConfigCmd.commands or {}
Zerotorescue@0 24 local commands = AceConfigCmd.commands
Zerotorescue@0 25
Zerotorescue@0 26 local cfgreg = LibStub("AceConfigRegistry-3.0")
Zerotorescue@0 27 local AceConsole -- LoD
Zerotorescue@0 28 local AceConsoleName = "AceConsole-3.0"
Zerotorescue@0 29
Zerotorescue@0 30 -- Lua APIs
Zerotorescue@0 31 local strsub, strsplit, strlower, strmatch, strtrim = string.sub, string.split, string.lower, string.match, string.trim
Zerotorescue@0 32 local format, tonumber, tostring = string.format, tonumber, tostring
Zerotorescue@0 33 local tsort, tinsert = table.sort, table.insert
Zerotorescue@0 34 local select, pairs, next, type = select, pairs, next, type
Zerotorescue@0 35 local error, assert = error, assert
Zerotorescue@0 36
Zerotorescue@0 37 -- WoW APIs
Zerotorescue@0 38 local _G = _G
Zerotorescue@0 39
Zerotorescue@0 40 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
Zerotorescue@0 41 -- List them here for Mikk's FindGlobals script
Zerotorescue@0 42 -- GLOBALS: LibStub, SELECTED_CHAT_FRAME, DEFAULT_CHAT_FRAME
Zerotorescue@0 43
Zerotorescue@0 44
Zerotorescue@0 45 local L = setmetatable({}, { -- TODO: replace with proper locale
Zerotorescue@0 46 __index = function(self,k) return k end
Zerotorescue@0 47 })
Zerotorescue@0 48
Zerotorescue@0 49
Zerotorescue@0 50
Zerotorescue@0 51 local function print(msg)
Zerotorescue@0 52 (SELECTED_CHAT_FRAME or DEFAULT_CHAT_FRAME):AddMessage(msg)
Zerotorescue@0 53 end
Zerotorescue@0 54
Zerotorescue@0 55 -- constants used by getparam() calls below
Zerotorescue@0 56
Zerotorescue@0 57 local handlertypes = {["table"]=true}
Zerotorescue@0 58 local handlermsg = "expected a table"
Zerotorescue@0 59
Zerotorescue@0 60 local functypes = {["function"]=true, ["string"]=true}
Zerotorescue@0 61 local funcmsg = "expected function or member name"
Zerotorescue@0 62
Zerotorescue@0 63
Zerotorescue@0 64 -- pickfirstset() - picks the first non-nil value and returns it
Zerotorescue@0 65
Zerotorescue@0 66 local function pickfirstset(...)
Zerotorescue@0 67 for i=1,select("#",...) do
Zerotorescue@0 68 if select(i,...)~=nil then
Zerotorescue@0 69 return select(i,...)
Zerotorescue@0 70 end
Zerotorescue@0 71 end
Zerotorescue@0 72 end
Zerotorescue@0 73
Zerotorescue@0 74
Zerotorescue@0 75 -- err() - produce real error() regarding malformed options tables etc
Zerotorescue@0 76
Zerotorescue@0 77 local function err(info,inputpos,msg )
Zerotorescue@0 78 local cmdstr=" "..strsub(info.input, 1, inputpos-1)
Zerotorescue@0 79 error(MAJOR..": /" ..info[0] ..cmdstr ..": "..(msg or "malformed options table"), 2)
Zerotorescue@0 80 end
Zerotorescue@0 81
Zerotorescue@0 82
Zerotorescue@0 83 -- usererr() - produce chatframe message regarding bad slash syntax etc
Zerotorescue@0 84
Zerotorescue@0 85 local function usererr(info,inputpos,msg )
Zerotorescue@0 86 local cmdstr=strsub(info.input, 1, inputpos-1);
Zerotorescue@0 87 print("/" ..info[0] .. " "..cmdstr ..": "..(msg or "malformed options table"))
Zerotorescue@0 88 end
Zerotorescue@0 89
Zerotorescue@0 90
Zerotorescue@0 91 -- callmethod() - call a given named method (e.g. "get", "set") with given arguments
Zerotorescue@0 92
Zerotorescue@0 93 local function callmethod(info, inputpos, tab, methodtype, ...)
Zerotorescue@0 94 local method = info[methodtype]
Zerotorescue@0 95 if not method then
Zerotorescue@0 96 err(info, inputpos, "'"..methodtype.."': not set")
Zerotorescue@0 97 end
Zerotorescue@0 98
Zerotorescue@0 99 info.arg = tab.arg
Zerotorescue@0 100 info.option = tab
Zerotorescue@0 101 info.type = tab.type
Zerotorescue@0 102
Zerotorescue@0 103 if type(method)=="function" then
Zerotorescue@0 104 return method(info, ...)
Zerotorescue@0 105 elseif type(method)=="string" then
Zerotorescue@0 106 if type(info.handler[method])~="function" then
Zerotorescue@0 107 err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler))
Zerotorescue@0 108 end
Zerotorescue@0 109 return info.handler[method](info.handler, info, ...)
Zerotorescue@0 110 else
Zerotorescue@0 111 assert(false) -- type should have already been checked on read
Zerotorescue@0 112 end
Zerotorescue@0 113 end
Zerotorescue@0 114
Zerotorescue@0 115 -- callfunction() - call a given named function (e.g. "name", "desc") with given arguments
Zerotorescue@0 116
Zerotorescue@0 117 local function callfunction(info, tab, methodtype, ...)
Zerotorescue@0 118 local method = tab[methodtype]
Zerotorescue@0 119
Zerotorescue@0 120 info.arg = tab.arg
Zerotorescue@0 121 info.option = tab
Zerotorescue@0 122 info.type = tab.type
Zerotorescue@0 123
Zerotorescue@0 124 if type(method)=="function" then
Zerotorescue@0 125 return method(info, ...)
Zerotorescue@0 126 else
Zerotorescue@0 127 assert(false) -- type should have already been checked on read
Zerotorescue@0 128 end
Zerotorescue@0 129 end
Zerotorescue@0 130
Zerotorescue@0 131 -- do_final() - do the final step (set/execute) along with validation and confirmation
Zerotorescue@0 132
Zerotorescue@0 133 local function do_final(info, inputpos, tab, methodtype, ...)
Zerotorescue@0 134 if info.validate then
Zerotorescue@0 135 local res = callmethod(info,inputpos,tab,"validate",...)
Zerotorescue@0 136 if type(res)=="string" then
Zerotorescue@0 137 usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res)
Zerotorescue@0 138 return
Zerotorescue@0 139 end
Zerotorescue@0 140 end
Zerotorescue@0 141 -- console ignores .confirm
Zerotorescue@0 142
Zerotorescue@0 143 callmethod(info,inputpos,tab,methodtype, ...)
Zerotorescue@0 144 end
Zerotorescue@0 145
Zerotorescue@0 146
Zerotorescue@0 147 -- getparam() - used by handle() to retreive and store "handler", "get", "set", etc
Zerotorescue@0 148
Zerotorescue@0 149 local function getparam(info, inputpos, tab, depth, paramname, types, errormsg)
Zerotorescue@0 150 local old,oldat = info[paramname], info[paramname.."_at"]
Zerotorescue@0 151 local val=tab[paramname]
Zerotorescue@0 152 if val~=nil then
Zerotorescue@0 153 if val==false then
Zerotorescue@0 154 val=nil
Zerotorescue@0 155 elseif not types[type(val)] then
Zerotorescue@0 156 err(info, inputpos, "'" .. paramname.. "' - "..errormsg)
Zerotorescue@0 157 end
Zerotorescue@0 158 info[paramname] = val
Zerotorescue@0 159 info[paramname.."_at"] = depth
Zerotorescue@0 160 end
Zerotorescue@0 161 return old,oldat
Zerotorescue@0 162 end
Zerotorescue@0 163
Zerotorescue@0 164
Zerotorescue@0 165 -- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.*
Zerotorescue@0 166 local dummytable={}
Zerotorescue@0 167
Zerotorescue@0 168 local function iterateargs(tab)
Zerotorescue@0 169 if not tab.plugins then
Zerotorescue@0 170 return pairs(tab.args)
Zerotorescue@0 171 end
Zerotorescue@0 172
Zerotorescue@0 173 local argtabkey,argtab=next(tab.plugins)
Zerotorescue@0 174 local v
Zerotorescue@0 175
Zerotorescue@0 176 return function(_, k)
Zerotorescue@0 177 while argtab do
Zerotorescue@0 178 k,v = next(argtab, k)
Zerotorescue@0 179 if k then return k,v end
Zerotorescue@0 180 if argtab==tab.args then
Zerotorescue@0 181 argtab=nil
Zerotorescue@0 182 else
Zerotorescue@0 183 argtabkey,argtab = next(tab.plugins, argtabkey)
Zerotorescue@0 184 if not argtabkey then
Zerotorescue@0 185 argtab=tab.args
Zerotorescue@0 186 end
Zerotorescue@0 187 end
Zerotorescue@0 188 end
Zerotorescue@0 189 end
Zerotorescue@0 190 end
Zerotorescue@0 191
Zerotorescue@0 192 local function checkhidden(info, inputpos, tab)
Zerotorescue@0 193 if tab.cmdHidden~=nil then
Zerotorescue@0 194 return tab.cmdHidden
Zerotorescue@0 195 end
Zerotorescue@0 196 local hidden = tab.hidden
Zerotorescue@0 197 if type(hidden) == "function" or type(hidden) == "string" then
Zerotorescue@0 198 info.hidden = hidden
Zerotorescue@0 199 hidden = callmethod(info, inputpos, tab, 'hidden')
Zerotorescue@0 200 info.hidden = nil
Zerotorescue@0 201 end
Zerotorescue@0 202 return hidden
Zerotorescue@0 203 end
Zerotorescue@0 204
Zerotorescue@0 205 local function showhelp(info, inputpos, tab, depth, noHead)
Zerotorescue@0 206 if not noHead then
Zerotorescue@0 207 print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":")
Zerotorescue@0 208 end
Zerotorescue@0 209
Zerotorescue@0 210 local sortTbl = {} -- [1..n]=name
Zerotorescue@0 211 local refTbl = {} -- [name]=tableref
Zerotorescue@0 212
Zerotorescue@0 213 for k,v in iterateargs(tab) do
Zerotorescue@0 214 if not refTbl[k] then -- a plugin overriding something in .args
Zerotorescue@0 215 tinsert(sortTbl, k)
Zerotorescue@0 216 refTbl[k] = v
Zerotorescue@0 217 end
Zerotorescue@0 218 end
Zerotorescue@0 219
Zerotorescue@0 220 tsort(sortTbl, function(one, two)
Zerotorescue@0 221 local o1 = refTbl[one].order or 100
Zerotorescue@0 222 local o2 = refTbl[two].order or 100
Zerotorescue@0 223 if type(o1) == "function" or type(o1) == "string" then
Zerotorescue@0 224 info.order = o1
Zerotorescue@0 225 info[#info+1] = one
Zerotorescue@0 226 o1 = callmethod(info, inputpos, refTbl[one], "order")
Zerotorescue@0 227 info[#info] = nil
Zerotorescue@0 228 info.order = nil
Zerotorescue@0 229 end
Zerotorescue@0 230 if type(o2) == "function" or type(o1) == "string" then
Zerotorescue@0 231 info.order = o2
Zerotorescue@0 232 info[#info+1] = two
Zerotorescue@0 233 o2 = callmethod(info, inputpos, refTbl[two], "order")
Zerotorescue@0 234 info[#info] = nil
Zerotorescue@0 235 info.order = nil
Zerotorescue@0 236 end
Zerotorescue@0 237 if o1<0 and o2<0 then return o1<o2 end
Zerotorescue@0 238 if o2<0 then return true end
Zerotorescue@0 239 if o1<0 then return false end
Zerotorescue@0 240 if o1==o2 then return tostring(one)<tostring(two) end -- compare names
Zerotorescue@0 241 return o1<o2
Zerotorescue@0 242 end)
Zerotorescue@0 243
Zerotorescue@0 244 for i = 1, #sortTbl do
Zerotorescue@0 245 local k = sortTbl[i]
Zerotorescue@0 246 local v = refTbl[k]
Zerotorescue@0 247 if not checkhidden(info, inputpos, v) then
Zerotorescue@0 248 if v.type ~= "description" and v.type ~= "header" then
Zerotorescue@0 249 -- recursively show all inline groups
Zerotorescue@0 250 local name, desc = v.name, v.desc
Zerotorescue@0 251 if type(name) == "function" then
Zerotorescue@0 252 name = callfunction(info, v, 'name')
Zerotorescue@0 253 end
Zerotorescue@0 254 if type(desc) == "function" then
Zerotorescue@0 255 desc = callfunction(info, v, 'desc')
Zerotorescue@0 256 end
Zerotorescue@0 257 if v.type == "group" and pickfirstset(v.cmdInline, v.inline, false) then
Zerotorescue@0 258 print(" "..(desc or name)..":")
Zerotorescue@0 259 local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg)
Zerotorescue@0 260 showhelp(info, inputpos, v, depth, true)
Zerotorescue@0 261 info.handler,info.handler_at = oldhandler,oldhandler_at
Zerotorescue@0 262 else
Zerotorescue@0 263 local key = k:gsub(" ", "_")
Zerotorescue@0 264 print(" |cffffff78"..key.."|r - "..(desc or name or ""))
Zerotorescue@0 265 end
Zerotorescue@0 266 end
Zerotorescue@0 267 end
Zerotorescue@0 268 end
Zerotorescue@0 269 end
Zerotorescue@0 270
Zerotorescue@0 271
Zerotorescue@0 272 local function keybindingValidateFunc(text)
Zerotorescue@0 273 if text == nil or text == "NONE" then
Zerotorescue@0 274 return nil
Zerotorescue@0 275 end
Zerotorescue@0 276 text = text:upper()
Zerotorescue@0 277 local shift, ctrl, alt
Zerotorescue@0 278 local modifier
Zerotorescue@0 279 while true do
Zerotorescue@0 280 if text == "-" then
Zerotorescue@0 281 break
Zerotorescue@0 282 end
Zerotorescue@0 283 modifier, text = strsplit('-', text, 2)
Zerotorescue@0 284 if text then
Zerotorescue@0 285 if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then
Zerotorescue@0 286 return false
Zerotorescue@0 287 end
Zerotorescue@0 288 if modifier == "SHIFT" then
Zerotorescue@0 289 if shift then
Zerotorescue@0 290 return false
Zerotorescue@0 291 end
Zerotorescue@0 292 shift = true
Zerotorescue@0 293 end
Zerotorescue@0 294 if modifier == "CTRL" then
Zerotorescue@0 295 if ctrl then
Zerotorescue@0 296 return false
Zerotorescue@0 297 end
Zerotorescue@0 298 ctrl = true
Zerotorescue@0 299 end
Zerotorescue@0 300 if modifier == "ALT" then
Zerotorescue@0 301 if alt then
Zerotorescue@0 302 return false
Zerotorescue@0 303 end
Zerotorescue@0 304 alt = true
Zerotorescue@0 305 end
Zerotorescue@0 306 else
Zerotorescue@0 307 text = modifier
Zerotorescue@0 308 break
Zerotorescue@0 309 end
Zerotorescue@0 310 end
Zerotorescue@0 311 if text == "" then
Zerotorescue@0 312 return false
Zerotorescue@0 313 end
Zerotorescue@0 314 if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then
Zerotorescue@0 315 return false
Zerotorescue@0 316 end
Zerotorescue@0 317 local s = text
Zerotorescue@0 318 if shift then
Zerotorescue@0 319 s = "SHIFT-" .. s
Zerotorescue@0 320 end
Zerotorescue@0 321 if ctrl then
Zerotorescue@0 322 s = "CTRL-" .. s
Zerotorescue@0 323 end
Zerotorescue@0 324 if alt then
Zerotorescue@0 325 s = "ALT-" .. s
Zerotorescue@0 326 end
Zerotorescue@0 327 return s
Zerotorescue@0 328 end
Zerotorescue@0 329
Zerotorescue@0 330 -- handle() - selfrecursing function that processes input->optiontable
Zerotorescue@0 331 -- - depth - starts at 0
Zerotorescue@0 332 -- - retfalse - return false rather than produce error if a match is not found (used by inlined groups)
Zerotorescue@0 333
Zerotorescue@0 334 local function handle(info, inputpos, tab, depth, retfalse)
Zerotorescue@0 335
Zerotorescue@0 336 if not(type(tab)=="table" and type(tab.type)=="string") then err(info,inputpos) end
Zerotorescue@0 337
Zerotorescue@0 338 -------------------------------------------------------------------
Zerotorescue@0 339 -- Grab hold of handler,set,get,func,etc if set (and remember old ones)
Zerotorescue@0 340 -- Note that we do NOT validate if method names are correct at this stage,
Zerotorescue@0 341 -- the handler may change before they're actually used!
Zerotorescue@0 342
Zerotorescue@0 343 local oldhandler,oldhandler_at = getparam(info,inputpos,tab,depth,"handler",handlertypes,handlermsg)
Zerotorescue@0 344 local oldset,oldset_at = getparam(info,inputpos,tab,depth,"set",functypes,funcmsg)
Zerotorescue@0 345 local oldget,oldget_at = getparam(info,inputpos,tab,depth,"get",functypes,funcmsg)
Zerotorescue@0 346 local oldfunc,oldfunc_at = getparam(info,inputpos,tab,depth,"func",functypes,funcmsg)
Zerotorescue@0 347 local oldvalidate,oldvalidate_at = getparam(info,inputpos,tab,depth,"validate",functypes,funcmsg)
Zerotorescue@0 348 --local oldconfirm,oldconfirm_at = getparam(info,inputpos,tab,depth,"confirm",functypes,funcmsg)
Zerotorescue@0 349
Zerotorescue@0 350 -------------------------------------------------------------------
Zerotorescue@0 351 -- Act according to .type of this table
Zerotorescue@0 352
Zerotorescue@0 353 if tab.type=="group" then
Zerotorescue@0 354 ------------ group --------------------------------------------
Zerotorescue@0 355
Zerotorescue@0 356 if type(tab.args)~="table" then err(info, inputpos) end
Zerotorescue@0 357 if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end
Zerotorescue@0 358
Zerotorescue@0 359 -- grab next arg from input
Zerotorescue@0 360 local _,nextpos,arg = (info.input):find(" *([^ ]+) *", inputpos)
Zerotorescue@0 361 if not arg then
Zerotorescue@0 362 showhelp(info, inputpos, tab, depth)
Zerotorescue@0 363 return
Zerotorescue@0 364 end
Zerotorescue@0 365 nextpos=nextpos+1
Zerotorescue@0 366
Zerotorescue@0 367 -- loop .args and try to find a key with a matching name
Zerotorescue@0 368 for k,v in iterateargs(tab) do
Zerotorescue@0 369 if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end
Zerotorescue@0 370
Zerotorescue@0 371 -- is this child an inline group? if so, traverse into it
Zerotorescue@0 372 if v.type=="group" and pickfirstset(v.cmdInline, v.inline, false) then
Zerotorescue@0 373 info[depth+1] = k
Zerotorescue@0 374 if handle(info, inputpos, v, depth+1, true)==false then
Zerotorescue@0 375 info[depth+1] = nil
Zerotorescue@0 376 -- wasn't found in there, but that's ok, we just keep looking down here
Zerotorescue@0 377 else
Zerotorescue@0 378 return -- done, name was found in inline group
Zerotorescue@0 379 end
Zerotorescue@0 380 -- matching name and not a inline group
Zerotorescue@0 381 elseif strlower(arg)==strlower(k:gsub(" ", "_")) then
Zerotorescue@0 382 info[depth+1] = k
Zerotorescue@0 383 return handle(info,nextpos,v,depth+1)
Zerotorescue@0 384 end
Zerotorescue@0 385 end
Zerotorescue@0 386
Zerotorescue@0 387 -- no match
Zerotorescue@0 388 if retfalse then
Zerotorescue@0 389 -- restore old infotable members and return false to indicate failure
Zerotorescue@0 390 info.handler,info.handler_at = oldhandler,oldhandler_at
Zerotorescue@0 391 info.set,info.set_at = oldset,oldset_at
Zerotorescue@0 392 info.get,info.get_at = oldget,oldget_at
Zerotorescue@0 393 info.func,info.func_at = oldfunc,oldfunc_at
Zerotorescue@0 394 info.validate,info.validate_at = oldvalidate,oldvalidate_at
Zerotorescue@0 395 --info.confirm,info.confirm_at = oldconfirm,oldconfirm_at
Zerotorescue@0 396 return false
Zerotorescue@0 397 end
Zerotorescue@0 398
Zerotorescue@0 399 -- couldn't find the command, display error
Zerotorescue@0 400 usererr(info, inputpos, "'"..arg.."' - " .. L["unknown argument"])
Zerotorescue@0 401 return
Zerotorescue@0 402 end
Zerotorescue@0 403
Zerotorescue@0 404 local str = strsub(info.input,inputpos);
Zerotorescue@0 405
Zerotorescue@0 406 if tab.type=="execute" then
Zerotorescue@0 407 ------------ execute --------------------------------------------
Zerotorescue@0 408 do_final(info, inputpos, tab, "func")
Zerotorescue@0 409
Zerotorescue@0 410
Zerotorescue@0 411
Zerotorescue@0 412 elseif tab.type=="input" then
Zerotorescue@0 413 ------------ input --------------------------------------------
Zerotorescue@0 414
Zerotorescue@0 415 local res = true
Zerotorescue@0 416 if tab.pattern then
Zerotorescue@0 417 if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end
Zerotorescue@0 418 if not strmatch(str, tab.pattern) then
Zerotorescue@0 419 usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
Zerotorescue@0 420 return
Zerotorescue@0 421 end
Zerotorescue@0 422 end
Zerotorescue@0 423
Zerotorescue@0 424 do_final(info, inputpos, tab, "set", str)
Zerotorescue@0 425
Zerotorescue@0 426
Zerotorescue@0 427
Zerotorescue@0 428 elseif tab.type=="toggle" then
Zerotorescue@0 429 ------------ toggle --------------------------------------------
Zerotorescue@0 430 local b
Zerotorescue@0 431 local str = strtrim(strlower(str))
Zerotorescue@0 432 if str=="" then
Zerotorescue@0 433 b = callmethod(info, inputpos, tab, "get")
Zerotorescue@0 434
Zerotorescue@0 435 if tab.tristate then
Zerotorescue@0 436 --cycle in true, nil, false order
Zerotorescue@0 437 if b then
Zerotorescue@0 438 b = nil
Zerotorescue@0 439 elseif b == nil then
Zerotorescue@0 440 b = false
Zerotorescue@0 441 else
Zerotorescue@0 442 b = true
Zerotorescue@0 443 end
Zerotorescue@0 444 else
Zerotorescue@0 445 b = not b
Zerotorescue@0 446 end
Zerotorescue@0 447
Zerotorescue@0 448 elseif str==L["on"] then
Zerotorescue@0 449 b = true
Zerotorescue@0 450 elseif str==L["off"] then
Zerotorescue@0 451 b = false
Zerotorescue@0 452 elseif tab.tristate and str==L["default"] then
Zerotorescue@0 453 b = nil
Zerotorescue@0 454 else
Zerotorescue@0 455 if tab.tristate then
Zerotorescue@0 456 usererr(info, inputpos, format(L["'%s' - expected 'on', 'off' or 'default', or no argument to toggle."], str))
Zerotorescue@0 457 else
Zerotorescue@0 458 usererr(info, inputpos, format(L["'%s' - expected 'on' or 'off', or no argument to toggle."], str))
Zerotorescue@0 459 end
Zerotorescue@0 460 return
Zerotorescue@0 461 end
Zerotorescue@0 462
Zerotorescue@0 463 do_final(info, inputpos, tab, "set", b)
Zerotorescue@0 464
Zerotorescue@0 465
Zerotorescue@0 466 elseif tab.type=="range" then
Zerotorescue@0 467 ------------ range --------------------------------------------
Zerotorescue@0 468 local val = tonumber(str)
Zerotorescue@0 469 if not val then
Zerotorescue@0 470 usererr(info, inputpos, "'"..str.."' - "..L["expected number"])
Zerotorescue@0 471 return
Zerotorescue@0 472 end
Zerotorescue@0 473 if type(info.step)=="number" then
Zerotorescue@0 474 val = val- (val % info.step)
Zerotorescue@0 475 end
Zerotorescue@0 476 if type(info.min)=="number" and val<info.min then
Zerotorescue@0 477 usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(info.min)) )
Zerotorescue@0 478 return
Zerotorescue@0 479 end
Zerotorescue@0 480 if type(info.max)=="number" and val>info.max then
Zerotorescue@0 481 usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(info.max)) )
Zerotorescue@0 482 return
Zerotorescue@0 483 end
Zerotorescue@0 484
Zerotorescue@0 485 do_final(info, inputpos, tab, "set", val)
Zerotorescue@0 486
Zerotorescue@0 487
Zerotorescue@0 488 elseif tab.type=="select" then
Zerotorescue@0 489 ------------ select ------------------------------------
Zerotorescue@0 490 local str = strtrim(strlower(str))
Zerotorescue@0 491
Zerotorescue@0 492 local values = tab.values
Zerotorescue@0 493 if type(values) == "function" or type(values) == "string" then
Zerotorescue@0 494 info.values = values
Zerotorescue@0 495 values = callmethod(info, inputpos, tab, "values")
Zerotorescue@0 496 info.values = nil
Zerotorescue@0 497 end
Zerotorescue@0 498
Zerotorescue@0 499 if str == "" then
Zerotorescue@0 500 local b = callmethod(info, inputpos, tab, "get")
Zerotorescue@0 501 local fmt = "|cffffff78- [%s]|r %s"
Zerotorescue@0 502 local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
Zerotorescue@0 503 print(L["Options for |cffffff78"..info[#info].."|r:"])
Zerotorescue@0 504 for k, v in pairs(values) do
Zerotorescue@0 505 if b == k then
Zerotorescue@0 506 print(fmt_sel:format(k, v))
Zerotorescue@0 507 else
Zerotorescue@0 508 print(fmt:format(k, v))
Zerotorescue@0 509 end
Zerotorescue@0 510 end
Zerotorescue@0 511 return
Zerotorescue@0 512 end
Zerotorescue@0 513
Zerotorescue@0 514 local ok
Zerotorescue@0 515 for k,v in pairs(values) do
Zerotorescue@0 516 if strlower(k)==str then
Zerotorescue@0 517 str = k -- overwrite with key (in case of case mismatches)
Zerotorescue@0 518 ok = true
Zerotorescue@0 519 break
Zerotorescue@0 520 end
Zerotorescue@0 521 end
Zerotorescue@0 522 if not ok then
Zerotorescue@0 523 usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"])
Zerotorescue@0 524 return
Zerotorescue@0 525 end
Zerotorescue@0 526
Zerotorescue@0 527 do_final(info, inputpos, tab, "set", str)
Zerotorescue@0 528
Zerotorescue@0 529 elseif tab.type=="multiselect" then
Zerotorescue@0 530 ------------ multiselect -------------------------------------------
Zerotorescue@0 531 local str = strtrim(strlower(str))
Zerotorescue@0 532
Zerotorescue@0 533 local values = tab.values
Zerotorescue@0 534 if type(values) == "function" or type(values) == "string" then
Zerotorescue@0 535 info.values = values
Zerotorescue@0 536 values = callmethod(info, inputpos, tab, "values")
Zerotorescue@0 537 info.values = nil
Zerotorescue@0 538 end
Zerotorescue@0 539
Zerotorescue@0 540 if str == "" then
Zerotorescue@0 541 local fmt = "|cffffff78- [%s]|r %s"
Zerotorescue@0 542 local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
Zerotorescue@0 543 print(L["Options for |cffffff78"..info[#info].."|r (multiple possible):"])
Zerotorescue@0 544 for k, v in pairs(values) do
Zerotorescue@0 545 if callmethod(info, inputpos, tab, "get", k) then
Zerotorescue@0 546 print(fmt_sel:format(k, v))
Zerotorescue@0 547 else
Zerotorescue@0 548 print(fmt:format(k, v))
Zerotorescue@0 549 end
Zerotorescue@0 550 end
Zerotorescue@0 551 return
Zerotorescue@0 552 end
Zerotorescue@0 553
Zerotorescue@0 554 --build a table of the selections, checking that they exist
Zerotorescue@0 555 --parse for =on =off =default in the process
Zerotorescue@0 556 --table will be key = true for options that should toggle, key = [on|off|default] for options to be set
Zerotorescue@0 557 local sels = {}
Zerotorescue@0 558 for v in str:gmatch("[^ ]+") do
Zerotorescue@0 559 --parse option=on etc
Zerotorescue@0 560 local opt, val = v:match('(.+)=(.+)')
Zerotorescue@0 561 --get option if toggling
Zerotorescue@0 562 if not opt then
Zerotorescue@0 563 opt = v
Zerotorescue@0 564 end
Zerotorescue@0 565
Zerotorescue@0 566 --check that the opt is valid
Zerotorescue@0 567 local ok
Zerotorescue@0 568 for k,v in pairs(values) do
Zerotorescue@0 569 if strlower(k)==opt then
Zerotorescue@0 570 opt = k -- overwrite with key (in case of case mismatches)
Zerotorescue@0 571 ok = true
Zerotorescue@0 572 break
Zerotorescue@0 573 end
Zerotorescue@0 574 end
Zerotorescue@0 575
Zerotorescue@0 576 if not ok then
Zerotorescue@0 577 usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"])
Zerotorescue@0 578 return
Zerotorescue@0 579 end
Zerotorescue@0 580
Zerotorescue@0 581 --check that if val was supplied it is valid
Zerotorescue@0 582 if val then
Zerotorescue@0 583 if val == L["on"] or val == L["off"] or (tab.tristate and val == L["default"]) then
Zerotorescue@0 584 --val is valid insert it
Zerotorescue@0 585 sels[opt] = val
Zerotorescue@0 586 else
Zerotorescue@0 587 if tab.tristate then
Zerotorescue@0 588 usererr(info, inputpos, format(L["'%s' '%s' - expected 'on', 'off' or 'default', or no argument to toggle."], v, val))
Zerotorescue@0 589 else
Zerotorescue@0 590 usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val))
Zerotorescue@0 591 end
Zerotorescue@0 592 return
Zerotorescue@0 593 end
Zerotorescue@0 594 else
Zerotorescue@0 595 -- no val supplied, toggle
Zerotorescue@0 596 sels[opt] = true
Zerotorescue@0 597 end
Zerotorescue@0 598 end
Zerotorescue@0 599
Zerotorescue@0 600 for opt, val in pairs(sels) do
Zerotorescue@0 601 local newval
Zerotorescue@0 602
Zerotorescue@0 603 if (val == true) then
Zerotorescue@0 604 --toggle the option
Zerotorescue@0 605 local b = callmethod(info, inputpos, tab, "get", opt)
Zerotorescue@0 606
Zerotorescue@0 607 if tab.tristate then
Zerotorescue@0 608 --cycle in true, nil, false order
Zerotorescue@0 609 if b then
Zerotorescue@0 610 b = nil
Zerotorescue@0 611 elseif b == nil then
Zerotorescue@0 612 b = false
Zerotorescue@0 613 else
Zerotorescue@0 614 b = true
Zerotorescue@0 615 end
Zerotorescue@0 616 else
Zerotorescue@0 617 b = not b
Zerotorescue@0 618 end
Zerotorescue@0 619 newval = b
Zerotorescue@0 620 else
Zerotorescue@0 621 --set the option as specified
Zerotorescue@0 622 if val==L["on"] then
Zerotorescue@0 623 newval = true
Zerotorescue@0 624 elseif val==L["off"] then
Zerotorescue@0 625 newval = false
Zerotorescue@0 626 elseif val==L["default"] then
Zerotorescue@0 627 newval = nil
Zerotorescue@0 628 end
Zerotorescue@0 629 end
Zerotorescue@0 630
Zerotorescue@0 631 do_final(info, inputpos, tab, "set", opt, newval)
Zerotorescue@0 632 end
Zerotorescue@0 633
Zerotorescue@0 634
Zerotorescue@0 635 elseif tab.type=="color" then
Zerotorescue@0 636 ------------ color --------------------------------------------
Zerotorescue@0 637 local str = strtrim(strlower(str))
Zerotorescue@0 638 if str == "" then
Zerotorescue@0 639 --TODO: Show current value
Zerotorescue@0 640 return
Zerotorescue@0 641 end
Zerotorescue@0 642
Zerotorescue@0 643 local r, g, b, a
Zerotorescue@0 644
Zerotorescue@0 645 if tab.hasAlpha then
Zerotorescue@0 646 if str:len() == 8 and str:find("^%x*$") then
Zerotorescue@0 647 --parse a hex string
Zerotorescue@0 648 r,g,b,a = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255, tonumber(str:sub(7, 8), 16) / 255
Zerotorescue@0 649 else
Zerotorescue@0 650 --parse seperate values
Zerotorescue@0 651 r,g,b,a = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$")
Zerotorescue@0 652 r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
Zerotorescue@0 653 end
Zerotorescue@0 654 if not (r and g and b and a) then
Zerotorescue@0 655 usererr(info, inputpos, format(L["'%s' - expected 'RRGGBBAA' or 'r g b a'."], str))
Zerotorescue@0 656 return
Zerotorescue@0 657 end
Zerotorescue@0 658
Zerotorescue@0 659 if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 and a >= 0.0 and a <= 1.0 then
Zerotorescue@0 660 --values are valid
Zerotorescue@0 661 elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 and a >= 0 and a <= 255 then
Zerotorescue@0 662 --values are valid 0..255, convert to 0..1
Zerotorescue@0 663 r = r / 255
Zerotorescue@0 664 g = g / 255
Zerotorescue@0 665 b = b / 255
Zerotorescue@0 666 a = a / 255
Zerotorescue@0 667 else
Zerotorescue@0 668 --values are invalid
Zerotorescue@0 669 usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0..1 or 0..255."], str))
Zerotorescue@0 670 end
Zerotorescue@0 671 else
Zerotorescue@0 672 a = 1.0
Zerotorescue@0 673 if str:len() == 6 and str:find("^%x*$") then
Zerotorescue@0 674 --parse a hex string
Zerotorescue@0 675 r,g,b = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255
Zerotorescue@0 676 else
Zerotorescue@0 677 --parse seperate values
Zerotorescue@0 678 r,g,b = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+)$")
Zerotorescue@0 679 r,g,b = tonumber(r), tonumber(g), tonumber(b)
Zerotorescue@0 680 end
Zerotorescue@0 681 if not (r and g and b) then
Zerotorescue@0 682 usererr(info, inputpos, format(L["'%s' - expected 'RRGGBB' or 'r g b'."], str))
Zerotorescue@0 683 return
Zerotorescue@0 684 end
Zerotorescue@0 685 if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 then
Zerotorescue@0 686 --values are valid
Zerotorescue@0 687 elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 then
Zerotorescue@0 688 --values are valid 0..255, convert to 0..1
Zerotorescue@0 689 r = r / 255
Zerotorescue@0 690 g = g / 255
Zerotorescue@0 691 b = b / 255
Zerotorescue@0 692 else
Zerotorescue@0 693 --values are invalid
Zerotorescue@0 694 usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0-1 or 0-255."], str))
Zerotorescue@0 695 end
Zerotorescue@0 696 end
Zerotorescue@0 697
Zerotorescue@0 698 do_final(info, inputpos, tab, "set", r,g,b,a)
Zerotorescue@0 699
Zerotorescue@0 700 elseif tab.type=="keybinding" then
Zerotorescue@0 701 ------------ keybinding --------------------------------------------
Zerotorescue@0 702 local str = strtrim(strlower(str))
Zerotorescue@0 703 if str == "" then
Zerotorescue@0 704 --TODO: Show current value
Zerotorescue@0 705 return
Zerotorescue@0 706 end
Zerotorescue@0 707 local value = keybindingValidateFunc(str:upper())
Zerotorescue@0 708 if value == false then
Zerotorescue@0 709 usererr(info, inputpos, format(L["'%s' - Invalid Keybinding."], str))
Zerotorescue@0 710 return
Zerotorescue@0 711 end
Zerotorescue@0 712
Zerotorescue@0 713 do_final(info, inputpos, tab, "set", value)
Zerotorescue@0 714
Zerotorescue@0 715 elseif tab.type=="description" then
Zerotorescue@0 716 ------------ description --------------------
Zerotorescue@0 717 -- ignore description, GUI config only
Zerotorescue@0 718 else
Zerotorescue@0 719 err(info, inputpos, "unknown options table item type '"..tostring(tab.type).."'")
Zerotorescue@0 720 end
Zerotorescue@0 721 end
Zerotorescue@0 722
Zerotorescue@0 723 --- Handle the chat command.
Zerotorescue@0 724 -- This is usually called from a chat command handler to parse the command input as operations on an aceoptions table.\\
Zerotorescue@0 725 -- AceConfigCmd uses this function internally when a slash command is registered with `:CreateChatCommand`
Zerotorescue@0 726 -- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
Zerotorescue@0 727 -- @param appName The application name as given to `:RegisterOptionsTable()`
Zerotorescue@0 728 -- @param input The commandline input (as given by the WoW handler, i.e. without the command itself)
Zerotorescue@0 729 -- @usage
Zerotorescue@0 730 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceConsole-3.0")
Zerotorescue@0 731 -- -- Use AceConsole-3.0 to register a Chat Command
Zerotorescue@0 732 -- MyAddon:RegisterChatCommand("mychat", "ChatCommand")
Zerotorescue@0 733 --
Zerotorescue@0 734 -- -- Show the GUI if no input is supplied, otherwise handle the chat input.
Zerotorescue@0 735 -- function MyAddon:ChatCommand(input)
Zerotorescue@0 736 -- -- Assuming "MyOptions" is the appName of a valid options table
Zerotorescue@0 737 -- if not input or input:trim() == "" then
Zerotorescue@0 738 -- LibStub("AceConfigDialog-3.0"):Open("MyOptions")
Zerotorescue@0 739 -- else
Zerotorescue@0 740 -- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input)
Zerotorescue@0 741 -- end
Zerotorescue@0 742 -- end
Zerotorescue@0 743 function AceConfigCmd:HandleCommand(slashcmd, appName, input)
Zerotorescue@0 744
Zerotorescue@0 745 local optgetter = cfgreg:GetOptionsTable(appName)
Zerotorescue@0 746 if not optgetter then
Zerotorescue@0 747 error([[Usage: HandleCommand("slashcmd", "appName", "input"): 'appName' - no options table "]]..tostring(appName)..[[" has been registered]], 2)
Zerotorescue@0 748 end
Zerotorescue@0 749 local options = assert( optgetter("cmd", MAJOR) )
Zerotorescue@0 750
Zerotorescue@0 751 local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot
Zerotorescue@0 752 [0] = slashcmd,
Zerotorescue@0 753 appName = appName,
Zerotorescue@0 754 options = options,
Zerotorescue@0 755 input = input,
Zerotorescue@0 756 self = self,
Zerotorescue@0 757 handler = self,
Zerotorescue@0 758 uiType = "cmd",
Zerotorescue@0 759 uiName = MAJOR,
Zerotorescue@0 760 }
Zerotorescue@0 761
Zerotorescue@0 762 handle(info, 1, options, 0) -- (info, inputpos, table, depth)
Zerotorescue@0 763 end
Zerotorescue@0 764
Zerotorescue@0 765 --- Utility function to create a slash command handler.
Zerotorescue@0 766 -- Also registers tab completion with AceTab
Zerotorescue@0 767 -- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
Zerotorescue@0 768 -- @param appName The application name as given to `:RegisterOptionsTable()`
Zerotorescue@0 769 function AceConfigCmd:CreateChatCommand(slashcmd, appName)
Zerotorescue@0 770 if not AceConsole then
Zerotorescue@0 771 AceConsole = LibStub(AceConsoleName)
Zerotorescue@0 772 end
Zerotorescue@0 773 if AceConsole.RegisterChatCommand(self, slashcmd, function(input)
Zerotorescue@0 774 AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
Zerotorescue@0 775 end,
Zerotorescue@0 776 true) then -- succesfully registered so lets get the command -> app table in
Zerotorescue@0 777 commands[slashcmd] = appName
Zerotorescue@0 778 end
Zerotorescue@0 779 end
Zerotorescue@0 780
Zerotorescue@0 781 --- Utility function that returns the options table that belongs to a slashcommand.
Zerotorescue@0 782 -- Designed to be used for the AceTab interface.
Zerotorescue@0 783 -- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
Zerotorescue@0 784 -- @return The options table associated with the slash command (or nil if the slash command was not registered)
Zerotorescue@0 785 function AceConfigCmd:GetChatCommandOptions(slashcmd)
Zerotorescue@0 786 return commands[slashcmd]
Zerotorescue@0 787 end