annotate 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
rev   line source
flickerstreak@1 1 --[[
flickerstreak@1 2 Name: AceTab-2.0
flickerstreak@1 3 Revision: $Rev: 18708 $
flickerstreak@1 4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
flickerstreak@1 5 Website: http://www.wowace.com/
flickerstreak@1 6 Documentation: http://www..wowace.com/index.php/AceTab-2.0
flickerstreak@1 7 SVN: http://svn.wowace.com/root/trunk/Ace2/AceTab-2.0
flickerstreak@1 8 Description: A tab-completion library
flickerstreak@1 9 Dependencies: AceLibrary, AceEvent-2.0
flickerstreak@1 10 ]]
flickerstreak@1 11
flickerstreak@1 12 local MAJOR_VERSION = "AceTab-2.0"
flickerstreak@1 13 local MINOR_VERSION = "$Revision: 18708 $"
flickerstreak@1 14
flickerstreak@1 15 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
flickerstreak@1 16 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
flickerstreak@1 17
flickerstreak@1 18 local AceEvent
flickerstreak@1 19 local AceTab = {}
flickerstreak@1 20 local _G = getfenv()
flickerstreak@1 21
flickerstreak@1 22 local hookedFrames = {}
flickerstreak@1 23 local framesHooked = {}
flickerstreak@1 24
flickerstreak@1 25 function AceTab:RegisterTabCompletion(descriptor, regex, wlfunc, usage, editframes)
flickerstreak@1 26 self:argCheck(descriptor, 2, "string")
flickerstreak@1 27 self:argCheck(regex, 3, "string", "table")
flickerstreak@1 28 self:argCheck(wlfunc, 4, "string", "function", "nil")
flickerstreak@1 29 self:argCheck(usage, 5, "string", "function", "boolean", "nil")
flickerstreak@1 30 self:argCheck(editframe, 6, "string", "table", "nil")
flickerstreak@1 31
flickerstreak@1 32 if type(regex) == "string" then regex = {regex} end
flickerstreak@1 33
flickerstreak@1 34 if type(wlfunc) == "string" and type(self[wlfunc]) ~= "function" then
flickerstreak@1 35 self:error("Cannot register function %q; it does not exist", wlfunc)
flickerstreak@1 36 end
flickerstreak@1 37
flickerstreak@1 38 if type(usage) == "string" and type(self[usage]) ~= "function" then
flickerstreak@1 39 self:error("Cannot register usage function %q; it does not exist", usage)
flickerstreak@1 40 end
flickerstreak@1 41
flickerstreak@1 42 if not editframes then editframes = {"ChatFrameEditBox"} end
flickerstreak@1 43
flickerstreak@1 44 if type(editframes) == "table" and editframes.Show then editframes = {editframes:GetName()} end
flickerstreak@1 45
flickerstreak@1 46 for _, frame in pairs(editframes) do
flickerstreak@1 47 local Gframe
flickerstreak@1 48 if type(frame) == "table" then
flickerstreak@1 49 Gframe = frame
flickerstreak@1 50 frame = frame:GetName()
flickerstreak@1 51 else
flickerstreak@1 52 Gframe = _G[frame]
flickerstreak@1 53 end
flickerstreak@1 54
flickerstreak@1 55 if type(Gframe) ~= "table" or not Gframe.Show then
flickerstreak@1 56 self:error("Cannot register frame %q; it does not exist", frame)
flickerstreak@1 57 frame = nil
flickerstreak@1 58 end
flickerstreak@1 59
flickerstreak@1 60 if frame then
flickerstreak@1 61 if Gframe:GetFrameType() ~= "EditBox" then
flickerstreak@1 62 self:error("Cannot register frame %q; it is not an EditBox", frame)
flickerstreak@1 63 frame = nil
flickerstreak@1 64 else
flickerstreak@1 65 if AceEvent and AceEvent:IsFullyInitialized() then
flickerstreak@1 66 if not framesHooked[Gframe] then
flickerstreak@1 67 framesHooked[Gframe] = true
flickerstreak@1 68 local orig = Gframe:GetScript("OnTabPressed")
flickerstreak@1 69 if type(orig) ~= "function" then
flickerstreak@1 70 orig = function() end
flickerstreak@1 71 end
flickerstreak@1 72 Gframe:SetScript("OnTabPressed", function()
flickerstreak@1 73 if self:OnTabPressed(Gframe) then
flickerstreak@1 74 return orig()
flickerstreak@1 75 end
flickerstreak@1 76 end)
flickerstreak@1 77 Gframe.curMatch = 0
flickerstreak@1 78 Gframe.matches = {}
flickerstreak@1 79 Gframe.pMatchLen = 0
flickerstreak@1 80 end
flickerstreak@1 81 else
flickerstreak@1 82 hookedFrames[frame] = true
flickerstreak@1 83 end
flickerstreak@1 84 end
flickerstreak@1 85 end
flickerstreak@1 86 end
flickerstreak@1 87
flickerstreak@1 88 if not self.registry[descriptor] then
flickerstreak@1 89 self.registry[descriptor] = {}
flickerstreak@1 90 end
flickerstreak@1 91
flickerstreak@1 92 if not self.registry[descriptor][self] then
flickerstreak@1 93 self.registry[descriptor][self] = {}
flickerstreak@1 94 end
flickerstreak@1 95 self.registry[descriptor][self] = {patterns = regex, wlfunc = wlfunc, usage = usage, frames = editframes}
flickerstreak@1 96
flickerstreak@1 97
flickerstreak@1 98 if not AceEvent and AceLibrary:HasInstance("AceEvent-2.0") then
flickerstreak@1 99 external(AceTab, "AceEvent-2.0", AceLibrary("AceEvent-2.0"))
flickerstreak@1 100 end
flickerstreak@1 101 if AceEvent then
flickerstreak@1 102 if not self:IsEventRegistered("AceEvent_FullyInitialized") then
flickerstreak@1 103 self:RegisterEvent("AceEvent_FullyInitialized", "AceEvent_FullyInitialized", true)
flickerstreak@1 104 end
flickerstreak@1 105 end
flickerstreak@1 106 end
flickerstreak@1 107
flickerstreak@1 108 function AceTab:IsTabCompletionRegistered(descriptor)
flickerstreak@1 109 self:argCheck(descriptor, 2, "string")
flickerstreak@1 110 return self.registry[descriptor] and self.registry[descriptor][self]
flickerstreak@1 111 end
flickerstreak@1 112
flickerstreak@1 113 function AceTab:UnregisterTabCompletion(descriptor)
flickerstreak@1 114 self:argCheck(descriptor, 2, "string")
flickerstreak@1 115 if self.registry[descriptor] and self.registry[descriptor][self] then
flickerstreak@1 116 self.registry[descriptor][self] = nil
flickerstreak@1 117 else
flickerstreak@1 118 self:error("Cannot unregister a tab completion (%s) that you have not registered.", descriptor)
flickerstreak@1 119 end
flickerstreak@1 120 end
flickerstreak@1 121
flickerstreak@1 122 local GCS
flickerstreak@1 123 GCS = function(s1, s2)
flickerstreak@1 124 if not s1 and not s2 then return end
flickerstreak@1 125 if not s1 then s1 = s2 end
flickerstreak@1 126 if not s2 then s2 = s1 end
flickerstreak@1 127 local s1len, s2len = string.len(s1), string.len(s2)
flickerstreak@1 128 if s2len < s1len then
flickerstreak@1 129 s1, s2 = s2, s1
flickerstreak@1 130 end
flickerstreak@1 131 if string.find(string.lower(s2), string.lower(s1)) then
flickerstreak@1 132 return s1
flickerstreak@1 133 else
flickerstreak@1 134 return GCS(string.sub(s1, 1, -2), s2)
flickerstreak@1 135 end
flickerstreak@1 136 end
flickerstreak@1 137 local pos
flickerstreak@1 138 local function CycleTab()
flickerstreak@1 139 this.pMatchLen = string.len(this.lMatch)
flickerstreak@1 140 local cMatch = 0
flickerstreak@1 141 local matched = false
flickerstreak@1 142 for desc, mList in pairs(this.matches) do
flickerstreak@1 143 if not matched then
flickerstreak@1 144 for _, m in ipairs(mList) do
flickerstreak@1 145 cMatch = cMatch + 1
flickerstreak@1 146 if cMatch == this.curMatch then
flickerstreak@1 147 this.lMatch = m
flickerstreak@1 148 this.curMatch = this.curMatch + 1
flickerstreak@1 149 matched = true
flickerstreak@1 150 break
flickerstreak@1 151 end
flickerstreak@1 152 end
flickerstreak@1 153 end
flickerstreak@1 154 end
flickerstreak@1 155 if not matched then
flickerstreak@1 156 this.curMatch = 1
flickerstreak@1 157 this.lMatch = this.origWord
flickerstreak@1 158 end
flickerstreak@1 159 this:HighlightText(pos - this.pMatchLen, pos)
flickerstreak@1 160 this:Insert(this.lMatch)
flickerstreak@1 161 end
flickerstreak@1 162
flickerstreak@1 163 function AceTab:OnTabPressed()
flickerstreak@1 164 local ost = this:GetScript("OnTextSet")
flickerstreak@1 165 if type(ost) ~= "function" then
flickerstreak@1 166 ost = nil
flickerstreak@1 167 end
flickerstreak@1 168 if ost then this:SetScript("OnTextSet", nil) end
flickerstreak@1 169 if this:GetText() == "" then return true end
flickerstreak@1 170 this:Insert("\255")
flickerstreak@1 171 pos = string.find(this:GetText(), "\255", 1) - 1
flickerstreak@1 172 this:HighlightText(pos, pos+1)
flickerstreak@1 173 this:Insert("\0")
flickerstreak@1 174 if ost then this:SetScript("OnTextSet", ost) end
flickerstreak@1 175 local fulltext = this:GetText()
flickerstreak@1 176 local text = string.sub(fulltext, 0, pos) or ""
flickerstreak@1 177
flickerstreak@1 178 local left = string.find(string.sub(text, 1, pos), "%w+$")
flickerstreak@1 179 left = left and left-1 or pos
flickerstreak@1 180 if not left or left == 1 and string.sub(text, 1, 1) == "/" then return true end
flickerstreak@1 181
flickerstreak@1 182 local _, _, word = string.find(string.sub(text, left, pos), "(%w+)")
flickerstreak@1 183 word = word or ""
flickerstreak@1 184 this.lMatch = this.curMatch > 0 and (this.lMatch or this.origWord)
flickerstreak@1 185
flickerstreak@1 186 if this.lMatch and this.lMatch ~= "" and string.find(string.sub(text, 1, pos), this.lMatch.."$") then
flickerstreak@1 187 return CycleTab()
flickerstreak@1 188 else
flickerstreak@1 189 this.matches = {}
flickerstreak@1 190 this.curMatch = 0
flickerstreak@1 191 this.lMatch = nil
flickerstreak@1 192 end
flickerstreak@1 193
flickerstreak@1 194 local completions = {}
flickerstreak@1 195 local numMatches = 0
flickerstreak@1 196 local firstMatch, hasNonFallback
flickerstreak@1 197
flickerstreak@1 198 for desc, entry in pairs(AceTab.registry) do
flickerstreak@1 199 for _, s in pairs(entry) do
flickerstreak@1 200 for _, f in pairs(s.frames) do
flickerstreak@1 201 if _G[f] == this then
flickerstreak@1 202 for _, regex in ipairs(s.patterns) do
flickerstreak@1 203 local cands = {}
flickerstreak@1 204 if string.find(string.sub(text, 1, left), regex.."$") then
flickerstreak@1 205 local c = s.wlfunc(cands, fulltext, left)
flickerstreak@1 206 if c ~= false then
flickerstreak@1 207 local mtemp = {}
flickerstreak@1 208 this.matches[desc] = this.matches[desc] or {}
flickerstreak@1 209 for _, cand in ipairs(cands) do
flickerstreak@1 210 if string.find(string.lower(cand), string.lower(word), 1, 1) == 1 then
flickerstreak@1 211 mtemp[cand] = true
flickerstreak@1 212 numMatches = numMatches + 1
flickerstreak@1 213 if numMatches == 1 then firstMatch = cand end
flickerstreak@1 214 end
flickerstreak@1 215 end
flickerstreak@1 216 for i in pairs(mtemp) do
flickerstreak@1 217 table.insert(this.matches[desc], i)
flickerstreak@1 218 end
flickerstreak@1 219 this.matches[desc].usage = s.usage
flickerstreak@1 220 if regex ~= "" and this.matches[desc][1] then
flickerstreak@1 221 hasNonFallback = true
flickerstreak@1 222 this.matches[desc].notFallback = true
flickerstreak@1 223 end
flickerstreak@1 224 end
flickerstreak@1 225 end
flickerstreak@1 226 end
flickerstreak@1 227 end
flickerstreak@1 228 end
flickerstreak@1 229 end
flickerstreak@1 230 end
flickerstreak@1 231
flickerstreak@1 232 local _, set = next(this.matches)
flickerstreak@1 233 if not set or numMatches == 0 and not hasNonFallback then return true end
flickerstreak@1 234
flickerstreak@1 235 this:HighlightText(left, left + string.len(word))
flickerstreak@1 236 if numMatches == 1 then
flickerstreak@1 237 this:Insert(firstMatch)
flickerstreak@1 238 this:Insert(" ")
flickerstreak@1 239 else
flickerstreak@1 240 if this.curMatch == 0 then
flickerstreak@1 241 this.curMatch = 1
flickerstreak@1 242 this.origWord = word
flickerstreak@1 243 this.lMatch = word
flickerstreak@1 244 CycleTab()
flickerstreak@1 245 end
flickerstreak@1 246 local gcs
flickerstreak@1 247 for h, c in pairs(this.matches) do
flickerstreak@1 248 if hasNonFallback and not c.notFallback then break end
flickerstreak@1 249 local u = c.usage
flickerstreak@1 250 c.usage = nil
flickerstreak@1 251 local candUsage = u and {}
flickerstreak@1 252 local gcs2
flickerstreak@1 253 if next(c) then
flickerstreak@1 254 if not u then DEFAULT_CHAT_FRAME:AddMessage(h..":") end
flickerstreak@1 255 for _, m in ipairs(c) do
flickerstreak@1 256 if not u then DEFAULT_CHAT_FRAME:AddMessage(m) end
flickerstreak@1 257 gcs2 = GCS(gcs2, m)
flickerstreak@1 258 end
flickerstreak@1 259 end
flickerstreak@1 260 gcs = GCS(gcs, gcs2)
flickerstreak@1 261 if u then
flickerstreak@1 262 if type(u) == "function" then
flickerstreak@1 263 local us = u(candUsage, c, gcs2, string.sub(text, 1, left))
flickerstreak@1 264 if candUsage and next(candUsage) then us = candUsage end
flickerstreak@1 265 if type(us) == "string" then
flickerstreak@1 266 DEFAULT_CHAT_FRAME:AddMessage(us)
flickerstreak@1 267 elseif type(us) == "table" and numMatches > 0 then
flickerstreak@1 268 for _, v in ipairs(c) do
flickerstreak@1 269 if us[v] then DEFAULT_CHAT_FRAME:AddMessage(string.format("%s - %s", v, us[v])) end
flickerstreak@1 270 end
flickerstreak@1 271 end
flickerstreak@1 272 end
flickerstreak@1 273 end
flickerstreak@1 274 end
flickerstreak@1 275 if curMatch == 0 then
flickerstreak@1 276 this:Insert(gcs or word)
flickerstreak@1 277 end
flickerstreak@1 278 end
flickerstreak@1 279 end
flickerstreak@1 280
flickerstreak@1 281 function AceTab:AceEvent_FullyInitialized()
flickerstreak@1 282 for frame in pairs(hookedFrames) do
flickerstreak@1 283 local Gframe = _G[frame]
flickerstreak@1 284 if not framesHooked[Gframe] then
flickerstreak@1 285 framesHooked[Gframe] = true
flickerstreak@1 286 local orig = Gframe:GetScript("OnTabPressed")
flickerstreak@1 287 if type(orig) ~= "function" then
flickerstreak@1 288 orig = function() end
flickerstreak@1 289 end
flickerstreak@1 290 Gframe:SetScript("OnTabPressed", function()
flickerstreak@1 291 if self:OnTabPressed(Gframe) then
flickerstreak@1 292 return orig()
flickerstreak@1 293 end
flickerstreak@1 294 end)
flickerstreak@1 295 Gframe.curMatch = 0
flickerstreak@1 296 Gframe.matches = {}
flickerstreak@1 297 Gframe.pMatchLen = 0
flickerstreak@1 298 end
flickerstreak@1 299 end
flickerstreak@1 300 end
flickerstreak@1 301
flickerstreak@1 302 local function external(self, major, instance)
flickerstreak@1 303 if major == "AceEvent-2.0" then
flickerstreak@1 304 if not AceEvent then
flickerstreak@1 305 AceEvent = instance
flickerstreak@1 306
flickerstreak@1 307 AceEvent:embed(self)
flickerstreak@1 308 end
flickerstreak@1 309 end
flickerstreak@1 310 end
flickerstreak@1 311
flickerstreak@1 312 local function activate(self, oldLib, oldDeactivate)
flickerstreak@1 313 if oldLib then
flickerstreak@1 314 self.registry = oldLib.registry
flickerstreak@1 315 end
flickerstreak@1 316
flickerstreak@1 317 if not self.registry then
flickerstreak@1 318 self.registry = {}
flickerstreak@1 319 end
flickerstreak@1 320
flickerstreak@1 321 if oldDeactivate then
flickerstreak@1 322 oldDeactivate(oldLib)
flickerstreak@1 323 end
flickerstreak@1 324 end
flickerstreak@1 325
flickerstreak@1 326 AceLibrary:Register(AceTab, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
flickerstreak@1 327 AceTab = AceLibrary(MAJOR_VERSION)