Skip to content

Commit 26a3274

Browse files
Use breakpoint manager to track state of break points even when disconnected from node
1 parent 0aa330d commit 26a3274

5 files changed

Lines changed: 117 additions & 165 deletions

File tree

lib/Components/BreakPointPane.coffee

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ log = (msg) -> #console.log(msg)
66

77
{TreeView, TreeViewItem} = require './TreeView'
88

9-
gotoBreakpoint = (brk) ->
10-
{line} = brk
11-
{name} = brk.script
12-
atom.workspace.open(name, {
13-
initialLine: line
9+
gotoBreakpoint = (breakpoint) ->
10+
atom.workspace.open(breakpoint.script, {
11+
initialLine: breakpoint.line
1412
initialColumn: 0
1513
activatePane: true
1614
searchAllPanes: true
@@ -21,22 +19,11 @@ exports.create = (_debugger) ->
2119
builder =
2220
listBreakpoints: () ->
2321
log "builder.listBreakpoints"
24-
_debugger.listBreakpoints()
25-
.then (brks) ->
26-
Promise.map brks, (brk) ->
27-
log("processing breakpoint " + JSON.stringify(brk))
28-
if brk.script_id?
29-
return _debugger.getScriptById(brk.script_id)
30-
.then (script) ->
31-
brk.script = script
32-
return brk
33-
else if brk.script_name
34-
brk.script = { name: brk.script_name }
35-
return brk
22+
Promise.resolve(_debugger.breakpointManager.breakpoints)
3623

3724
breakpoint: (breakpoint) ->
3825
log "builder.breakpoint"
39-
TreeViewItem("#{breakpoint.script.name} : (#{breakpoint.line + 1})", handlers: { click: () -> gotoBreakpoint(breakpoint) })
26+
TreeViewItem("#{breakpoint.script} : (#{breakpoint.line+1})", handlers: { click: () -> gotoBreakpoint(breakpoint) })
4027

4128
root: () ->
4229
TreeView("Breakpoints", (() -> builder.listBreakpoints().map(builder.breakpoint)), isRoot: true)

lib/Components/ConsolePane.coffee

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ exports.create = (_debugger) ->
7979
next()
8080
})
8181

82-
_debugger.processManager.on 'procssCreated', ->
82+
_debugger.processManager.on 'processCreated', ->
8383
{stdout, stderr} = _debugger.processManager.process
8484

8585
stdout.on 'data', (d) -> console.log(d.toString())

lib/debugger.coffee

Lines changed: 105 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ childprocess = require 'child_process'
88
Event = require 'geval/event'
99
logger = require './logger'
1010

11+
log = (msg) -> #console.log(msg)
12+
1113
class ProcessManager extends EventEmitter
1214
constructor: (@atom = atom)->
1315
super()
@@ -30,10 +32,8 @@ class ProcessManager extends EventEmitter
3032
port = @atom.config.get('node-debugger.debugPort')
3133
env = @parseEnv @atom.config.get('node-debugger.env')
3234

33-
appPath = @atom
34-
.workspace
35-
.getActiveTextEditor()
36-
.getPath()
35+
editor = @atom.workspace.getActiveTextEditor()
36+
appPath = editor.getPath()
3737

3838
dbgFile = file or appPath
3939
cwd = path.dirname(dbgFile)
@@ -63,7 +63,7 @@ class ProcessManager extends EventEmitter
6363
@process.stderr.on 'end', () ->
6464
logger.info 'child_process', 'end error'
6565

66-
@emit 'procssCreated', @process
66+
@emit 'processCreated', @process
6767

6868
@process.once 'error', (err) =>
6969
switch err.code
@@ -112,33 +112,118 @@ class ProcessManager extends EventEmitter
112112
@process.once 'exit', onProcessEnd
113113
@process.once 'close', onProcessEnd
114114

115-
class Debugger extends EventEmitter
116-
constructor: (@atom = atom, @processManager)->
115+
class BreakpointManager extends EventEmitter
116+
constructor: (@debugger) ->
117117
super()
118+
log "BreakpointManager.constructor"
119+
self = this
118120
@breakpoints = []
119121
@client = null
120-
121-
@onBreakEvent = Event()
122+
@debugger.on 'connected', ->
123+
self.client = self.debugger.client
124+
log "BreakpointManager.connected #{@client}"
125+
self.attachBreakpoint breakpoint for breakpoint in self.breakpoints
126+
@debugger.on 'disconnected', ->
127+
log "BreakpointManager.disconnected"
128+
self.client = null
129+
for breakpoint in self.breakpoints
130+
breakpoint.id = null
131+
self.decorateBreakpoint breakpoint
122132
@onAddBreakpointEvent = Event()
123133
@onRemoveBreakpointEvent = Event()
134+
135+
toggleBreakpoint: (editor, script, line) ->
136+
log "BreakpointManager.toggleBreakpoint #{script}, #{line}"
137+
maybeBreakpoint = @tryFindBreakpoint script, line
138+
if maybeBreakpoint
139+
@removeBreakpoint maybeBreakpoint.breakpoint, maybeBreakpoint.index
140+
else
141+
@addBreakpoint editor, script, line
142+
143+
removeBreakpoint: (breakpoint, index) ->
144+
log "BreakpointManager.removeBreakpoint #{index}"
145+
@breakpoints.splice index, 1
146+
@onRemoveBreakpointEvent.broadcast breakpoint
147+
@detachBreakpoint breakpoint, 'removed'
148+
149+
addBreakpoint: (editor, script, line) ->
150+
log "BreakpointManager.addBreakpoint #{script}, #{line}"
151+
breakpoint =
152+
script: script
153+
line: line
154+
marker: null
155+
editor: editor
156+
id: null
157+
log "BreakpointManager.addBreakpoint - adding to list"
158+
@breakpoints.push breakpoint
159+
log "BreakpointManager.addBreakpoint - adding default decoration"
160+
@decorateBreakpoint breakpoint
161+
log "BreakpointManager.addBreakpoint - publishing event, num breakpoints=#{@breakpoints.length}"
162+
@onAddBreakpointEvent.broadcast breakpoint
163+
log "BreakpointManager.addBreakpoint - attaching"
164+
@attachBreakpoint breakpoint
165+
166+
attachBreakpoint: (breakpoint) ->
167+
log "BreakpointManager.attachBreakpoint"
168+
self = this
169+
new Promise (resolve, reject) ->
170+
return resolve() unless self.client
171+
log "BreakpointManager.attachBreakpoint - client request"
172+
self.client.setBreakpoint {
173+
type: 'script'
174+
target: breakpoint.script
175+
line: breakpoint.line
176+
condition: breakpoint.condition
177+
}, (err, res) ->
178+
log "BreakpointManager.attachBreakpoint - done"
179+
return reject(err) if err
180+
breakpoint.id = res.breakpoint
181+
self.decorateBreakpoint breakpoint
182+
resolve(breakpoint)
183+
184+
detachBreakpoint: (breakpoint, reason) ->
185+
log "BreakpointManager.detachBreakpoint"
186+
self = this
187+
new Promise (resolve, reject) ->
188+
id = breakpoint.id
189+
breakpoint.id = null
190+
breakpoint.marker.destroy()
191+
breakpoint.marker = null
192+
return resolve() unless self.client
193+
return resolve() unless id
194+
log "BreakpointManager.detachBreakpoint - client request"
195+
self.client.clearBreakpoint {
196+
breakpoint: id
197+
}, (err) ->
198+
self.decorateBreakpoint breakpoint unless reason is 'removed'
199+
resolve()
200+
201+
tryFindBreakpoint: (script, line) ->
202+
return { breakpoint: breakpoint, index: i } for breakpoint, i in @breakpoints when breakpoint.script is script and breakpoint.line is line
203+
204+
decorateBreakpoint: (breakpoint) ->
205+
log "BreakpointManager.decorateBreakpoint - #{breakpoint.marker is null}"
206+
breakpoint.marker.destroy() if breakpoint.marker
207+
breakpoint.marker = breakpoint.editor.markBufferPosition([breakpoint.line, 0], invalidate: 'never')
208+
className = if breakpoint.id then 'node-debugger-attached-breakpoint' else 'node-debugger-detached-breakpoint'
209+
breakpoint.editor.decorateMarker(breakpoint.marker, type: 'line-number', class: className)
210+
211+
class Debugger extends EventEmitter
212+
constructor: (@atom, @processManager)->
213+
super()
214+
@client = null
215+
@breakpointManager = new BreakpointManager(this)
216+
@onBreakEvent = Event()
124217
@onBreak = @onBreakEvent.listen
125-
@onAddBreakpoint = @onAddBreakpointEvent.listen
126-
@onRemoveBreakpoint = @onRemoveBreakpointEvent.listen
127-
@processManager.on 'procssCreated', @start
218+
@onAddBreakpoint = @breakpointManager.onAddBreakpointEvent.listen
219+
@onRemoveBreakpoint = @breakpointManager.onRemoveBreakpointEvent.listen
220+
@processManager.on 'processCreated', @start
128221
@processManager.on 'processEnd', @cleanup
129-
@markers = []
130222

131223
stopRetrying: ->
132224
return unless @timeout?
133225
clearTimeout @timeout
134226

135-
136-
listBreakpoints: ->
137-
new Promise (resolve, reject) =>
138-
@client.listbreakpoints (err, res) ->
139-
return reject(err) if err
140-
resolve(res.breakpoints)
141-
142227
step: (type, count) ->
143228
self = this
144229
new Promise (resolve, reject) =>
@@ -168,113 +253,6 @@ class Debugger extends EventEmitter
168253
return reject(err) if err
169254
resolve(res[0])
170255

171-
tryGetBreakpoint: (script, line) =>
172-
findMatch = R.find (breakpoint) =>
173-
if breakpoint.scriptId is script or breakpoint.scriptReq is script or (breakpoint.script and breakpoint.script.indexOf(script) isnt -1)
174-
return breakpoint.line is (line+1);
175-
return findMatch(@client.breakpoints)
176-
177-
toggleBreakpoint: (editor, script, line) ->
178-
new Promise (resolve, reject) =>
179-
180-
match = @tryGetBreakpoint(script, line)
181-
if match
182-
@clearBreakPoint(script, line)
183-
else
184-
@addBreakpoint(editor, script, line)
185-
186-
addBreakpoint: (editor, script, line, condition, silent) =>
187-
new Promise (resolve, reject) =>
188-
if script is undefined
189-
script = @client.currentScript;
190-
line = @client.currentSourceLine + 1
191-
192-
if line is undefined and typeof script is 'number'
193-
line = script
194-
script = @client.currentScript
195-
196-
return if not script?
197-
198-
if /\(\)$/.test(script)
199-
req =
200-
type: 'function'
201-
target: script.replace /\(\)$/, ''
202-
confition: condition
203-
else
204-
if script != +script && not @client.scripts[script]
205-
scripts = @client.scripts
206-
for id in scripts
207-
if scripts[id] and scripts[id].name and scripts.name.indexOf(script) isnt -1
208-
ambiguous = scriptId?
209-
scriptId = id
210-
else
211-
scriptId = script
212-
213-
if line <= 0
214-
return reject(new Error('Line should be a positive value'))
215-
if ambiguous
216-
return reject(new Error('Invalid script name'))
217-
218-
if scriptId?
219-
req =
220-
type: 'scriptId'
221-
target: scriptId
222-
line: line - 1
223-
condition: condition
224-
else
225-
escapedPath = script.replace(/([/\\.?*()^${}|[\]])/g, '\\$1')
226-
scriptPathRegex = "^(.*[\\/\\\\])?#{escapedPath}$";
227-
req =
228-
type: 'script'
229-
target: script
230-
line: line
231-
condition: condition
232-
233-
@client.setBreakpoint req, (err, res) =>
234-
return reject(err) if err
235-
236-
if not scriptId?
237-
scriptId = res.script_id
238-
line = res.line + 1
239-
240-
brk =
241-
id: res.breakpoint
242-
scriptId: scriptId
243-
script: (@client?.scripts?[scriptId] or {}).name
244-
line: line,
245-
condition: condition,
246-
scriptReq: script
247-
248-
@client.breakpoints.push brk
249-
brk.marker = @markLine(editor, brk)
250-
@onAddBreakpointEvent.broadcast(brk)
251-
resolve(brk)
252-
253-
254-
clearBreakPoint: (script, line) ->
255-
self = this
256-
getbrk =
257-
() ->
258-
new Promise (resolve, reject) =>
259-
match = self.tryGetBreakpoint(script, line)
260-
return reject() if not match?
261-
resolve({
262-
breakpoint: match
263-
index: self.client.breakpoints.indexOf match
264-
})
265-
clearbrk =
266-
(brk) ->
267-
new Promise (resolve, reject) =>
268-
self.client.clearBreakpoint { breakpoint: brk.breakpoint.id }, (err) =>
269-
return reject(err) if err
270-
self.client.breakpoints.splice brk.index, 1
271-
markerIndex = self.markers.indexOf(brk.breakpoint.marker)
272-
self.markers.splice(markerIndex, 1)
273-
brk.breakpoint.marker.destroy()
274-
self.onRemoveBreakpointEvent.broadcast(brk)
275-
resolve()
276-
277-
getbrk().then(clearbrk)
278256

279257
fullTrace: () ->
280258
new Promise (resolve, reject) =>
@@ -348,27 +326,10 @@ class Debugger extends EventEmitter
348326

349327
cleanup: =>
350328
return unless @client?
351-
@removeBreakpointMarkers()
352-
@removeDecorations()
353329
@client.destroy()
354330
@client = null
355331
@emit 'disconnected'
356332

357-
markLine: (editor, breakPoint) ->
358-
marker = editor.markBufferPosition([breakPoint.line-1, 0], invalidate: 'never')
359-
editor.decorateMarker(marker, type: 'line-number', class: 'node-debugger-breakpoint')
360-
@markers.push marker
361-
return marker
362-
363-
removeBreakpointMarkers: =>
364-
return unless @client?
365-
breakpoint.marker.destroy() for breakpoint in @client.breakpoints
366-
367-
removeDecorations: ->
368-
return unless @markers?
369-
marker.destroy() for marker in @markers
370-
@markers = []
371-
372333
isConnected: =>
373334
return @client?
374335

lib/node-debugger.coffee

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ module.exports =
7171
editor = atom.workspace.getActiveTextEditor()
7272
path = editor.getPath()
7373
{row} = editor.getCursorBufferPosition()
74-
_debugger.toggleBreakpoint(editor, path, row)
74+
_debugger.breakpointManager.toggleBreakpoint editor, path, row
7575

7676
stepNext: =>
7777
_debugger.step('next', 1)

styles/node-debugger.less

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@ atom-text-editor::shadow {
4040
color: @text-color
4141
}
4242

43-
&.node-debugger-breakpoint {
43+
&.node-debugger-attached-breakpoint {
4444
background-color: #F00;
4545
}
46+
47+
&.node-debugger-detached-breakpoint {
48+
background-color: #FF850B;
49+
}
4650
}
4751
}

0 commit comments

Comments
 (0)