Mercurial > wow > reaction
diff libs/AceTab-2.0/AceTab-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/AceTab-2.0/AceTab-2.0.lua Tue Mar 20 21:03:57 2007 +0000 @@ -0,0 +1,327 @@ +--[[ +Name: AceTab-2.0 +Revision: $Rev: 18708 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Website: http://www.wowace.com/ +Documentation: http://www..wowace.com/index.php/AceTab-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceTab-2.0 +Description: A tab-completion library +Dependencies: AceLibrary, AceEvent-2.0 +]] + +local MAJOR_VERSION = "AceTab-2.0" +local MINOR_VERSION = "$Revision: 18708 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local AceEvent +local AceTab = {} +local _G = getfenv() + +local hookedFrames = {} +local framesHooked = {} + +function AceTab:RegisterTabCompletion(descriptor, regex, wlfunc, usage, editframes) + self:argCheck(descriptor, 2, "string") + self:argCheck(regex, 3, "string", "table") + self:argCheck(wlfunc, 4, "string", "function", "nil") + self:argCheck(usage, 5, "string", "function", "boolean", "nil") + self:argCheck(editframe, 6, "string", "table", "nil") + + if type(regex) == "string" then regex = {regex} end + + if type(wlfunc) == "string" and type(self[wlfunc]) ~= "function" then + self:error("Cannot register function %q; it does not exist", wlfunc) + end + + if type(usage) == "string" and type(self[usage]) ~= "function" then + self:error("Cannot register usage function %q; it does not exist", usage) + end + + if not editframes then editframes = {"ChatFrameEditBox"} end + + if type(editframes) == "table" and editframes.Show then editframes = {editframes:GetName()} end + + for _, frame in pairs(editframes) do + local Gframe + if type(frame) == "table" then + Gframe = frame + frame = frame:GetName() + else + Gframe = _G[frame] + end + + if type(Gframe) ~= "table" or not Gframe.Show then + self:error("Cannot register frame %q; it does not exist", frame) + frame = nil + end + + if frame then + if Gframe:GetFrameType() ~= "EditBox" then + self:error("Cannot register frame %q; it is not an EditBox", frame) + frame = nil + else + if AceEvent and AceEvent:IsFullyInitialized() then + if not framesHooked[Gframe] then + framesHooked[Gframe] = true + local orig = Gframe:GetScript("OnTabPressed") + if type(orig) ~= "function" then + orig = function() end + end + Gframe:SetScript("OnTabPressed", function() + if self:OnTabPressed(Gframe) then + return orig() + end + end) + Gframe.curMatch = 0 + Gframe.matches = {} + Gframe.pMatchLen = 0 + end + else + hookedFrames[frame] = true + end + end + end + end + + if not self.registry[descriptor] then + self.registry[descriptor] = {} + end + + if not self.registry[descriptor][self] then + self.registry[descriptor][self] = {} + end + self.registry[descriptor][self] = {patterns = regex, wlfunc = wlfunc, usage = usage, frames = editframes} + + + if not AceEvent and AceLibrary:HasInstance("AceEvent-2.0") then + external(AceTab, "AceEvent-2.0", AceLibrary("AceEvent-2.0")) + end + if AceEvent then + if not self:IsEventRegistered("AceEvent_FullyInitialized") then + self:RegisterEvent("AceEvent_FullyInitialized", "AceEvent_FullyInitialized", true) + end + end +end + +function AceTab:IsTabCompletionRegistered(descriptor) + self:argCheck(descriptor, 2, "string") + return self.registry[descriptor] and self.registry[descriptor][self] +end + +function AceTab:UnregisterTabCompletion(descriptor) + self:argCheck(descriptor, 2, "string") + if self.registry[descriptor] and self.registry[descriptor][self] then + self.registry[descriptor][self] = nil + else + self:error("Cannot unregister a tab completion (%s) that you have not registered.", descriptor) + end +end + +local GCS +GCS = function(s1, s2) + if not s1 and not s2 then return end + if not s1 then s1 = s2 end + if not s2 then s2 = s1 end + local s1len, s2len = string.len(s1), string.len(s2) + if s2len < s1len then + s1, s2 = s2, s1 + end + if string.find(string.lower(s2), string.lower(s1)) then + return s1 + else + return GCS(string.sub(s1, 1, -2), s2) + end +end +local pos +local function CycleTab() + this.pMatchLen = string.len(this.lMatch) + local cMatch = 0 + local matched = false + for desc, mList in pairs(this.matches) do + if not matched then + for _, m in ipairs(mList) do + cMatch = cMatch + 1 + if cMatch == this.curMatch then + this.lMatch = m + this.curMatch = this.curMatch + 1 + matched = true + break + end + end + end + end + if not matched then + this.curMatch = 1 + this.lMatch = this.origWord + end + this:HighlightText(pos - this.pMatchLen, pos) + this:Insert(this.lMatch) +end + +function AceTab:OnTabPressed() + local ost = this:GetScript("OnTextSet") + if type(ost) ~= "function" then + ost = nil + end + if ost then this:SetScript("OnTextSet", nil) end + if this:GetText() == "" then return true end + this:Insert("\255") + pos = string.find(this:GetText(), "\255", 1) - 1 + this:HighlightText(pos, pos+1) + this:Insert("\0") + if ost then this:SetScript("OnTextSet", ost) end + local fulltext = this:GetText() + local text = string.sub(fulltext, 0, pos) or "" + + local left = string.find(string.sub(text, 1, pos), "%w+$") + left = left and left-1 or pos + if not left or left == 1 and string.sub(text, 1, 1) == "/" then return true end + + local _, _, word = string.find(string.sub(text, left, pos), "(%w+)") + word = word or "" + this.lMatch = this.curMatch > 0 and (this.lMatch or this.origWord) + + if this.lMatch and this.lMatch ~= "" and string.find(string.sub(text, 1, pos), this.lMatch.."$") then + return CycleTab() + else + this.matches = {} + this.curMatch = 0 + this.lMatch = nil + end + + local completions = {} + local numMatches = 0 + local firstMatch, hasNonFallback + + for desc, entry in pairs(AceTab.registry) do + for _, s in pairs(entry) do + for _, f in pairs(s.frames) do + if _G[f] == this then + for _, regex in ipairs(s.patterns) do + local cands = {} + if string.find(string.sub(text, 1, left), regex.."$") then + local c = s.wlfunc(cands, fulltext, left) + if c ~= false then + local mtemp = {} + this.matches[desc] = this.matches[desc] or {} + for _, cand in ipairs(cands) do + if string.find(string.lower(cand), string.lower(word), 1, 1) == 1 then + mtemp[cand] = true + numMatches = numMatches + 1 + if numMatches == 1 then firstMatch = cand end + end + end + for i in pairs(mtemp) do + table.insert(this.matches[desc], i) + end + this.matches[desc].usage = s.usage + if regex ~= "" and this.matches[desc][1] then + hasNonFallback = true + this.matches[desc].notFallback = true + end + end + end + end + end + end + end + end + + local _, set = next(this.matches) + if not set or numMatches == 0 and not hasNonFallback then return true end + + this:HighlightText(left, left + string.len(word)) + if numMatches == 1 then + this:Insert(firstMatch) + this:Insert(" ") + else + if this.curMatch == 0 then + this.curMatch = 1 + this.origWord = word + this.lMatch = word + CycleTab() + end + local gcs + for h, c in pairs(this.matches) do + if hasNonFallback and not c.notFallback then break end + local u = c.usage + c.usage = nil + local candUsage = u and {} + local gcs2 + if next(c) then + if not u then DEFAULT_CHAT_FRAME:AddMessage(h..":") end + for _, m in ipairs(c) do + if not u then DEFAULT_CHAT_FRAME:AddMessage(m) end + gcs2 = GCS(gcs2, m) + end + end + gcs = GCS(gcs, gcs2) + if u then + if type(u) == "function" then + local us = u(candUsage, c, gcs2, string.sub(text, 1, left)) + if candUsage and next(candUsage) then us = candUsage end + if type(us) == "string" then + DEFAULT_CHAT_FRAME:AddMessage(us) + elseif type(us) == "table" and numMatches > 0 then + for _, v in ipairs(c) do + if us[v] then DEFAULT_CHAT_FRAME:AddMessage(string.format("%s - %s", v, us[v])) end + end + end + end + end + end + if curMatch == 0 then + this:Insert(gcs or word) + end + end +end + +function AceTab:AceEvent_FullyInitialized() + for frame in pairs(hookedFrames) do + local Gframe = _G[frame] + if not framesHooked[Gframe] then + framesHooked[Gframe] = true + local orig = Gframe:GetScript("OnTabPressed") + if type(orig) ~= "function" then + orig = function() end + end + Gframe:SetScript("OnTabPressed", function() + if self:OnTabPressed(Gframe) then + return orig() + end + end) + Gframe.curMatch = 0 + Gframe.matches = {} + Gframe.pMatchLen = 0 + end + end +end + +local function external(self, major, instance) + if major == "AceEvent-2.0" then + if not AceEvent then + AceEvent = instance + + AceEvent:embed(self) + end + end +end + +local 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) + end +end + +AceLibrary:Register(AceTab, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) +AceTab = AceLibrary(MAJOR_VERSION)