bzr branch
http://9ix.org/bzr/ld27
35
by Josh C
cluke009 zoetrope + my spritebatch changes |
1 |
debugger = debugger or {} |
2 |
||
3 |
-- Property: debugger.consoleKey |
|
4 |
-- What key toggles visibility. By default, this is the tab key. |
|
5 |
debugger.consoleKey = 'tab' |
|
6 |
||
7 |
-- Property: debugger.crashed |
|
8 |
-- Records whether the app has crashed. |
|
9 |
debugger.crashed = false |
|
10 |
||
11 |
-- internal property: debugger._sourceCache |
|
12 |
-- A cache of source files used by debugger.sourceLine(). |
|
13 |
debugger._sourceCache = {} |
|
14 |
||
15 |
-- Function: debugger.init() |
|
16 |
-- Adds debug instruments to the app. Must be called *after* |
|
17 |
-- an app has started running, i.e. in its <App.onRun> event |
|
18 |
-- handler. |
|
19 |
-- |
|
20 |
-- Arguments: |
|
21 |
-- Instrument classes to add, defaults to all available |
|
22 |
-- |
|
23 |
-- Returns: |
|
24 |
-- nothing |
|
25 |
||
26 |
debugger.init = function() |
|
27 |
debugger.console = Group:new |
|
28 |
{ |
|
29 |
visible = false, |
|
30 |
spacing = 10, |
|
31 |
instruments = { narrow = Group:new(), wide = Group:new() }, |
|
32 |
widths = { wide = 0.7, narrow = 0.3 }, |
|
33 |
listeners = {}, |
|
34 |
||
35 |
_instrumentHeights = {}, |
|
36 |
||
37 |
onNew = function (self) |
|
38 |
self:add(self.instruments.narrow) |
|
39 |
self:add(self.instruments.wide) |
|
40 |
end, |
|
41 |
||
42 |
update = function (self, elapsed) |
|
43 |
if the.keys:justPressed(debugger.consoleKey) then |
|
44 |
if self.visible then |
|
45 |
debugger.hideConsole() |
|
46 |
else |
|
47 |
debugger.showConsole() |
|
48 |
end |
|
49 |
end |
|
50 |
||
51 |
for _, listener in pairs(self.listeners) do |
|
52 |
listener() |
|
53 |
end |
|
54 |
||
55 |
if debugger.console.visible then |
|
56 |
for spr, height in pairs(debugger.console._instrumentHeights) do |
|
57 |
if height ~= spr.contentHeight then |
|
58 |
debugger._resizeInstruments() |
|
59 |
end |
|
60 |
end |
|
61 |
||
62 |
Group.update(self, elapsed) |
|
63 |
end |
|
64 |
end |
|
65 |
} |
|
66 |
||
67 |
the.app.meta:add(debugger.console) |
|
68 |
||
69 |
debugger.addInstrument(DebugStepper:new()) |
|
70 |
debugger.addInstrument(DebugLocals:new()) |
|
71 |
debugger.addInstrument(DebugStack:new()) |
|
72 |
debugger.addInstrument(DebugPerformance:new()) |
|
73 |
debugger.addInstrument(DebugWatch:new()) |
|
74 |
debugger.addInstrument(DebugShortcuts:new()) |
|
75 |
debugger.addInstrument(DebugConsole:new()) |
|
76 |
end |
|
77 |
||
78 |
-- Function: debugger.showConsole() |
|
79 |
-- Makes the console visible. |
|
80 |
-- |
|
81 |
-- Arguments: |
|
82 |
-- none |
|
83 |
-- |
|
84 |
-- Returns: |
|
85 |
-- nothing |
|
86 |
||
87 |
debugger.showConsole = function() |
|
88 |
debugger.console.visible = true |
|
89 |
end |
|
90 |
||
91 |
-- Function: debugger.hideConsole |
|
92 |
-- Makes the console invisible. If the app has crashed, |
|
93 |
-- this has no effect. |
|
94 |
-- |
|
95 |
-- Arguments: |
|
96 |
-- none |
|
97 |
-- |
|
98 |
-- Returns: |
|
99 |
-- nothing |
|
100 |
||
101 |
debugger.hideConsole = function() |
|
102 |
if not debugger.crashed then |
|
103 |
debugger.console.visible = false |
|
104 |
end |
|
105 |
end |
|
106 |
||
107 |
-- Function: debugger.addInstrument |
|
108 |
-- Adds an instrument to the console, creating a container and |
|
109 |
-- tab to select it. |
|
110 |
-- |
|
111 |
-- Arguments: |
|
112 |
-- instrument - <Group> enclosing the entire instrument |
|
113 |
-- |
|
114 |
-- Returns: |
|
115 |
-- nothing |
|
116 |
||
117 |
debugger.addInstrument = function (instrument) |
|
118 |
local console = debugger.console |
|
119 |
assert(instrument.width == 'narrow' or instrument.width == 'wide', |
|
120 |
"debug instrument's width property must be either 'wide' or 'narrow'") |
|
121 |
||
122 |
console.instruments[instrument.width]:add(instrument) |
|
123 |
debugger._resizeInstruments() |
|
124 |
end |
|
125 |
||
126 |
-- Function: debugger.addListener |
|
127 |
-- Adds a function that will be called on every frame, |
|
128 |
-- regardless of whether the console is visible. |
|
129 |
-- |
|
130 |
-- Arguments: |
|
131 |
-- listener - function |
|
132 |
-- |
|
133 |
-- Returns: |
|
134 |
-- nothing |
|
135 |
||
136 |
debugger.addListener = function (func) |
|
137 |
table.insert(debugger.console.listeners, func) |
|
138 |
end |
|
139 |
||
140 |
-- Function: debugger.reload |
|
141 |
-- Resets the entire app and forces all code to be reloaded from |
|
142 |
-- on disk. via https://love2d.org/forums/viewtopic.php?f=3&t=7965 |
|
143 |
-- |
|
144 |
-- Arguments: |
|
145 |
-- none |
|
146 |
-- |
|
147 |
-- Returns: |
|
148 |
-- nothing |
|
149 |
||
150 |
debugger.reload = function() |
|
151 |
love.audio.stop() |
|
152 |
||
153 |
-- create local references to needed variables |
|
154 |
-- because we're about to blow the global scope away |
|
155 |
||
156 |
local initialGlobals = debugger._initialGlobals |
|
157 |
local initialPackages = debugger._initialPackages |
|
158 |
||
159 |
-- reset global scope |
|
160 |
||
161 |
for key, _ in pairs(_G) do |
|
162 |
_G[key] = initialGlobals[key] |
|
163 |
end |
|
164 |
||
165 |
-- reload main file and restart |
|
166 |
||
167 |
for key, _ in pairs(package.loaded) do |
|
168 |
if not initialPackages[key] then |
|
169 |
package.loaded[key] = nil |
|
170 |
end |
|
171 |
end |
|
172 |
||
173 |
require('main') |
|
174 |
love.load() |
|
175 |
end |
|
176 |
||
177 |
-- Function: debugger.sourceLine |
|
178 |
-- Retrieves a line of source code. If the source file cannot |
|
179 |
-- be opened, then this returns '(source not available)'. If |
|
180 |
-- the line doesn't exist in the file (e.g. you ask for line 200 |
|
181 |
-- of a 100-line file), this returns nil. |
|
182 |
-- |
|
183 |
-- Arguments: |
|
184 |
-- file - filename of the source code |
|
185 |
-- line - line number to retrieve |
|
186 |
-- |
|
187 |
-- Returns: |
|
188 |
-- string source or '(source not available') |
|
189 |
||
190 |
debugger.sourceLine = function (file, line) |
|
191 |
if file then |
|
192 |
if not debugger._sourceCache[file] then |
|
193 |
debugger._sourceCache[file] = {} |
|
194 |
||
195 |
for line in love.filesystem.lines(file) do |
|
196 |
table.insert(debugger._sourceCache[file], line) |
|
197 |
end |
|
198 |
end |
|
199 |
||
200 |
return debugger._sourceCache[file][line] |
|
201 |
else |
|
202 |
return '(source not available)' |
|
203 |
end |
|
204 |
end |
|
205 |
||
206 |
debugger._resizeInstruments = function() |
|
207 |
local console = debugger.console |
|
208 |
||
209 |
-- wide instruments |
|
210 |
||
211 |
local x = console.spacing |
|
212 |
local y = console.spacing |
|
213 |
local width = the.app.width * console.widths.wide |
|
214 |
local expandables = {} |
|
215 |
||
216 |
for _, spr in pairs(console.instruments.wide.sprites) do |
|
217 |
if spr.visible then |
|
218 |
local height = spr:totalHeight() |
|
219 |
console._instrumentHeights[spr] = spr.contentHeight |
|
220 |
||
221 |
if height == '*' then |
|
222 |
table.insert(expandables, spr) |
|
223 |
else |
|
224 |
spr:resize(x, y, width - console.spacing, height) |
|
225 |
y = y + height + console.spacing |
|
226 |
end |
|
227 |
end |
|
228 |
end |
|
229 |
||
230 |
if #expandables > 0 then |
|
231 |
local height = (the.app.height - y) / #expandables |
|
232 |
||
233 |
for i, spr in ipairs(expandables) do |
|
234 |
spr:resize(x, y + height * (i - 1), width - console.spacing, height - console.spacing) |
|
235 |
end |
|
236 |
end |
|
237 |
||
238 |
-- narrow instruments |
|
239 |
||
240 |
x = x + width |
|
241 |
y = console.spacing |
|
242 |
width = the.app.width * console.widths.narrow |
|
243 |
expandables = {} |
|
244 |
||
245 |
for _, spr in pairs(console.instruments.narrow.sprites) do |
|
246 |
if spr.visible then |
|
247 |
local height = spr:totalHeight() |
|
248 |
console._instrumentHeights[spr] = spr.contentHeight |
|
249 |
||
250 |
if height == '*' then |
|
251 |
table.insert(expandables, spr) |
|
252 |
else |
|
253 |
spr:resize(x, y, width - 2 * console.spacing, height) |
|
254 |
y = y + height + console.spacing |
|
255 |
end |
|
256 |
end |
|
257 |
end |
|
258 |
||
259 |
if #expandables > 0 then |
|
260 |
local height = (the.app.height - y) / #expandables |
|
261 |
||
262 |
for i, spr in ipairs(expandables) do |
|
263 |
spr:resize(x, y + height * (i - 1), width - console.spacing, height - console.spacing) |
|
264 |
end |
|
265 |
end |
|
266 |
end |
|
267 |
||
268 |
-- internal function: debugger._miniEventLoop |
|
269 |
-- This replicates the entire LOVE event loop, but only updates/draws |
|
270 |
-- the debug console, keyboard, and mouse. This is so that after a crash or |
|
271 |
-- during a break, drawing and updates still continue to happen. |
|
272 |
-- |
|
273 |
-- Arguments: |
|
274 |
-- forever - run indefinitely, or just for a single frame? |
|
275 |
-- |
|
276 |
-- Returns: |
|
277 |
-- whether a quit event was detected, and the caller |
|
278 |
-- should take an action based on this |
|
279 |
||
280 |
debugger._miniEventLoop = function (forever) |
|
281 |
local elapsed = 0 |
|
282 |
local quitNow = false |
|
283 |
||
284 |
repeat |
|
285 |
if love.event then |
|
286 |
love.event.pump() |
|
287 |
||
288 |
for e, a, b, c, d in love.event.poll() do |
|
289 |
if e == 'quit' then |
|
290 |
if not love.quit or not love.quit() then |
|
291 |
quitNow = true |
|
292 |
forever = false |
|
293 |
end |
|
294 |
end |
|
295 |
||
296 |
love.handlers[e](a, b, c, d) |
|
297 |
end |
|
298 |
end |
|
299 |
||
300 |
if love.timer then |
|
301 |
love.timer.step() |
|
302 |
elapsed = love.timer.getDelta() |
|
303 |
end |
|
304 |
||
305 |
the.keys:startFrame(elapsed) |
|
306 |
the.mouse:startFrame(elapsed) |
|
307 |
debugger.console:startFrame(elapsed) |
|
308 |
the.keys:update(elapsed) |
|
309 |
the.mouse:update(elapsed) |
|
310 |
debugger.console:update(elapsed) |
|
311 |
the.keys:endFrame(elapsed) |
|
312 |
the.mouse:endFrame(elapsed) |
|
313 |
debugger.console:endFrame(elapsed) |
|
314 |
||
315 |
if the.keys:pressed('escape') then |
|
316 |
if not love.quit or not love.quit() then |
|
317 |
love.event.quit() |
|
318 |
end |
|
319 |
end |
|
320 |
||
321 |
if love.graphics then |
|
322 |
love.graphics.clear() |
|
323 |
if love.draw then |
|
324 |
debugger.console:draw() |
|
325 |
end |
|
326 |
end |
|
327 |
||
328 |
if love.timer then love.timer.sleep(0.03) end |
|
329 |
if love.graphics then love.graphics.present() end |
|
330 |
until not forever |
|
331 |
||
332 |
return quitNow |
|
333 |
end |