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