--[[Name: AceTab-2.0Revision: $Rev: 1$Author(s): hyperactiveChipmunk (hyperactiveChipmunk@gmail.com)Website: http://www.wowace.com/Documentation: http://wiki.wowace.com/index.php/AceTab-2.0SVN: http://svn.wowace.com/root/trunk/Ace2/AceConsoleDescription: Tab-completion functionalityDependencies: AceLibrary]]local MAJOR_VERSION = "AceTab-2.0"local MINOR_VERSION = "$Revision: 1 $"if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") endif not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return endlocal AceTab = {}local _G = getfenv()function AceTab:RegisterCompletion(descriptor, regex, compfunc, editframes, usagefunc) AceTab:argCheck(func, 2, "string", "function") AceTab:argCheck(descriptor, 3, "string") AceTab:argCheck(regex, 4, "string") AceTab:argCheck(editframe, 5, "string", "table", "nil") AceTab:argCheck(isCmd, 6, "string", "function", "nil") if type(compfunc) == "string" and type(self[compfunc]) ~= "function" then AceTab:error("Cannot register function %q; it does not exist", compfunc) end if type(editframes) == "string" then editframes = {_G[editframes]} end for i, frame in pairs(editframes) do if type(frame) == "string" then if type(self[frame]) ~= "table" then AceTab:Print("Cannot register frame %q; it does not exist", editframe) else editframes[i] = _G[frame] end if editframes[i] then if editframes[i]:GetFrameType() ~= "EditBox" then AceTab:Print("Cannot register frame %q; it is not an EditBox") editframes[i] = nil elseif not AceTab.hooks[frame] then AceTab:HookScript(editframe, "OnTabPressed") end end end end if type(usagefunc) == "string" and type(self[compfunc]) ~= "function" then AceTab:error("Cannot register usage function %q; it does not exist", usagefunc) end if not AceTab.registry[descriptor] then AceTab.registry[descriptor] = Compost and Compost:Acquire() or {} end if not AceTab.registry[descriptor][self] then AceTab.registry[descriptor][self] = Compost and Compost:Acquire() or {} end AceTab.registry[descriptor][self].patterns = regex AceTab.registry[descriptor][self].compfunc = compfunc AceTab.registry[descriptor][self].frames = editframes or {VisorEditBox} AceTab.registry[descriptor][self].usage = usagefuncendfunction AceTab:IsCompletionRegistered(descriptor) AceTab:argCheck(descriptor, 2, "string") if AceTab.registry[descriptor] and AceTab.registry[descriptor][self] then return true, AceTab.registry[descriptor][self].completion end return false, nilendfunction AceTab:UnregisterCompletion(descriptor) AceTab:argCheck(descriptor, 2, "string") if AceTab.registry[description] and AceTab.registry[description][self] then AceTab.registry[descriptor][self].completion = nil else AceTab:error("Cannot unregister a tab completion that you have not registered.") endendlocal function LCS(strings) --returns Least Common Substring. Yoinked wholesale from Tem. local len = 0 local numStrings = table.getn(strings) for _, s in strings do len = string.len(s) > len and string.len(s) or len end for i = 1, len do local c = string.sub(strings[1], i, i) for j = 2, numStrings do if string.sub(strings[j], i, i) ~= c then return string.sub(strings[1], 0, i-1) end end end return strings[1]endfunction AceTab:OnTabPressed() local completions = compost and compost:Erase() or {} --get position of the cursor local ost = this:GetScript("OnTextSet") if ost then this:SetScript("OnTextSet", nil) end this:Insert("\1") local pos = string.find(this:GetText(), "\1", 1) - 1 this:HighlightText(pos, pos+1) this:Insert("\0") if ost then this:SetScript("OnTextSet", ost) end local text = string.sub(this:GetText(), 0, pos) local left = string.find(string.sub(text, 0, pos), "[%S]+$") or string.len(cmd) local _, _, word = string.find(string.sub(text, left, pos), "^([%S]+)") for d, s in pairs(AceTab.registry) do for _, f in s.frames do if f == this then for _, regex in ipairs(s.patterns) do if string.find(text, regex) then hdr, cand = s[compfunc](word) if hdr and cand then table.insert(completions, { header = hdr, candidates = cand, usage = s.usage }) end end end end end end if not next(completions) then return end local matches = compost and compost:Erase() or {} for _, completion in ipairs(completions) do for cand in ipairs(completion.candidates) do if string.find(string.lower(cand), string.lower(word), nil, 1) == 1 and not matches.cand then matches.cand = true end end end local mSorted = compost and compost:Erase() or {} for match in pairs(matches) do table.insert(mSorted, match) end table.sort(mSorted) this:HighlightText(left - 1, left + string.len(word)) if table.getn(mSorted) == 1 then this:Insert(next(completions).candidates[1]) this:Insert(" ") else for header in pairs(completions) do AceTab:Print(header) for _, match in mSorted do local useageString = header.usage(match) if usageString then AceTab:Print(usageString) else print(match) end end end this:Insert(LCS(mSorted)) endendlocal function activate(self, oldLib, oldDeactivate) if oldLib then self.registry = oldLib.registry end if not self.registry then self.registry = {} end if oldDeactivate then oldDeactivate(oldLib) endendAceLibrary:Register(AceTab, MAJOR_VERSION, MINOR_VERSION, activate)AceTab = AceLibrary(MAJOR_VERSION)