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