add support for stack navigation, along with a bit more documentation

refactor some large blocks of code and add a few comments

svn: r8791
This commit is contained in:
Greg Cooper 2008-02-25 05:02:09 +00:00
parent c569701f4c
commit c4b76ea3dc
2 changed files with 382 additions and 273 deletions

View File

@ -79,15 +79,27 @@
(loop (add1 i)))
#f)))
;; trim-expr-str: string -> string
;; examples:
;; short-id => short-id
;; really-long-identifier => really-lon...
;; (<form>) => (<form>)
;; (<form> <arg1> ... <argn>) => (<form> ...)
(define (trim-expr-str str)
(cond
[(index-of #\newline str) => (lambda (i)
(string-append
(substring str 0 i)
(if (char=? (string-ref str 0) #\()
" ...)"
" ...")))]
[str]))
(let ([starts-with-paren (and (> (string-length str) 0))])
(cond
[(and starts-with-paren
(or (index-of #\space str)
(index-of #\newline str)
(and (> (string-length str) 14) 10)))
;; non-atomic expr: truncate to (form-name ...)
=> (lambda (i)
(string-append
(substring str 0 i)
(if starts-with-paren
" ...)"
" ...")))]
[str])))
(define (average . values)
(/ (apply + values) (length values)))
@ -117,8 +129,7 @@
(cond
[(is-a? source editor<%>) source]
[(or (not source) (symbol? source)) #f]
[(and source (not (symbol? source))
(send (group:get-the-frame-group) locate-file source))
[(send (group:get-the-frame-group) locate-file source)
=>
(lambda (frame)
(let ([defss (map (lambda (t) (send t get-defs)) (send frame get-tabs))])
@ -139,18 +150,27 @@
get-tab)
(define mouse-over-pos #f)
;; pen and brush for drawing a breakpoint
(define bp-pen (send the-pen-list find-or-create-pen "black" 1 'solid))
(define bp-brush (send the-brush-list find-or-create-brush "red" 'solid))
;; pen and brush for marking a location that could have a breakpoint installed
(define bp-mo-pen (send the-pen-list find-or-create-pen "darkgray" 1 'solid))
(define bp-mo-brush (send the-brush-list find-or-create-brush "tomato"
'solid))
;; pen and brush for marking a conditional breakpoint
(define bp-tmp-pen (send the-pen-list find-or-create-pen "black" 1 'solid))
(define bp-tmp-brush (send the-brush-list find-or-create-brush "yellow"
'solid))
;; pen and brush for drawing the normal execution location
(define pc-pen (send the-pen-list find-or-create-pen "black" 1 'solid))
(define pc-brush (send the-brush-list find-or-create-brush "forestgreen" 'solid))
;; pen and brush for marking the expression when not at the top of the stack
(define pc-up-stack-pen (send the-pen-list find-or-create-pen "black" 1 'solid))
(define pc-up-stack-brush (send the-brush-list find-or-create-brush "lightgreen" 'solid))
;; pen and brush for marking the location when there's an an error
(define pc-err-pen (send the-pen-list find-or-create-pen "black" 1 'solid))
(define pc-err-brush (send the-brush-list find-or-create-brush "red" 'solid))
;; pen and brush for marking the location following a break
(define pc-brk-pen (send the-pen-list find-or-create-pen "black" 1 'solid))
(define pc-brk-brush (send the-brush-list find-or-create-brush "gray" 'solid))
@ -192,8 +212,11 @@
breakpoints
(lambda (pos status)
(when (< start pos)
;; text inserted before this breakpoint, so shift
;; the breakpoint forward by <len> positions
(hash-table-remove! breakpoints pos)
(set! shifts (cons (cons (+ pos len) status) shifts)))))
;; update the breakpoint locations
(for-each (lambda (p) (hash-table-put! breakpoints (car p) (cdr p)))
shifts))
(inner (void) on-insert start len))
@ -204,6 +227,9 @@
(send (get-tab) hide-debug))
(end-edit-sequence))
;; lookup id in the given set of stack frames;
;; if that fails, try the top-level environment
;; invokes sk on success, fk on failure
(define (lookup-var id frames sk fk)
(cond
[(and id frames (lookup-first-binding
@ -222,6 +248,7 @@
(sk (tlb) tlb))]
[else (fk)]))
;; mouse-event -> (or (values #f #f) (values pos editor))
(define/private (get-pos/text event)
(let ([event-x (send event get-x)]
[event-y (send event get-y)]
@ -248,6 +275,9 @@
(values #f #f)))]
[else (values #f #f)])))))
;; text% start end -> (values left top right bottom)
;; (four numbers that indicate the locations in pixels of the
;; box bounding the text between start and end
(define/private (find-char-box text left-pos right-pos)
(let ([xlb (box 0)]
[ylb (box 0)]
@ -266,172 +296,179 @@
(define/private (render v)
(send (get-tab) render v))
(define (debugger-handle-right-click-non-breakable event pos)
(let* ([frames (send (get-tab) get-stack-frames)]
[pos-vec (send (get-tab) get-pos-vec)]
[id (robust-vector-ref pos-vec pos)])
(unless (lookup-var
id
frames
(lambda (val wr)
(let ([id-sym (syntax-e id)]
[menu (make-object popup-menu% #f)])
(make-object menu-item%
(clean-status
(format "Print value of ~a to console" id-sym))
menu
(lambda (item evt)
(send (get-tab) print-to-console (format "~a = ~a" id-sym val))))
(make-object menu-item%
(format "(set! ~a ...)" id-sym)
menu
(lambda (item evt)
(let* ([tmp
(get-text-from-user
(format "New value for ~a" id-sym) #f #f
(format "~a" val))])
(when tmp
(let/ec k
(wr (with-handlers
([exn:fail?
(lambda (exn)
(message-box
"Debugger Error"
(format "The following error occurred: ~a"
(exn-message exn)))
(k))])
(read (open-input-string tmp)))))))))
(send (get-canvas) popup-menu menu
(+ 1 (inexact->exact (floor (send event get-x))))
(+ 1 (inexact->exact (floor (send event get-y)))))
#t))
(lambda () #f))
(super on-event event))))
(define (debugger-handle-right-click-breakable event breakpoints pos break-status)
(let ([menu (make-object popup-menu% #f)])
(make-object menu-item%
(if break-status
"Remove pause at this point"
"Pause at this point")
menu
(lambda (item evt)
(hash-table-put! breakpoints pos (not break-status))
(invalidate-bitmap-cache)))
(let ([pc (send (get-tab) get-pc)])
(if (and pc (= pos pc))
(let* ([stat (send (get-tab) get-break-status)]
[f (get-top-level-window)]
[rendered-value
(if (cons? stat)
(if (= 2 (length stat))
(render (cadr stat))
(format "~a" (cons 'values
(map (lambda (v) (render v)) (rest stat)))))
"")])
(when (cons? stat)
(make-object menu-item%
"Print return value to console"
menu
(lambda _ (send (get-tab) print-to-console (format "return val = ~a"
rendered-value)))))
(when (not (eq? stat 'break))
(make-object menu-item%
(if (cons? stat)
"Change return value..."
"Skip expression...")
menu
(lambda (item evt)
(let ([tmp (get-text-from-user "Return value" #f)])
(when tmp
(let/ec k
(send (get-tab) set-break-status
(cons 'exit-break
(call-with-values
(lambda ()
(with-handlers
([exn:fail?
(lambda (exn)
(message-box
"Debugger Error"
(format "An error occurred: ~a" (exn-message exn))
#f
'(ok))
(k))])
(read (open-input-string tmp))))
list)))
(invalidate-bitmap-cache))))))))
(make-object menu-item%
"Continue to this point"
menu
(lambda (item evt)
(hash-table-put!
breakpoints pos
(lambda () (hash-table-put! breakpoints pos break-status) #t))
(invalidate-bitmap-cache)
(when (send (get-tab) get-stack-frames)
(send (get-tab) resume))))))
(send (get-canvas) popup-menu menu
(+ 1 (inexact->exact (floor (send event get-x))))
(+ 1 (inexact->exact (floor (send event get-y)))))))
(define (debugger-handle-right-click event breakpoints)
(let-values ([(pos text) (get-pos/text event)])
(if (and pos text)
(let* ([pos (add1 pos)]
[break-status (hash-table-get breakpoints pos (lambda () 'invalid))])
(match break-status
[(or #t #f (? procedure?))
(debugger-handle-right-click-breakable event breakpoints pos break-status)]
['invalid
(debugger-handle-right-click-non-breakable event pos)]))
(super on-event event))))
(define (debugger-handle-event event)
(let ([breakpoints (send (get-tab) get-breakpoints)])
(cond
[(send event leaving?)
(when mouse-over-pos
(set! mouse-over-pos #f)
(invalidate-bitmap-cache))
(super on-event event)]
[(or (send event moving?)
(send event entering?))
(let-values ([(pos text) (get-pos/text event)])
(when (and pos text)
(let ([pos (add1 pos)])
(cond
;; mouse on breakable pos and hasn't moved significantly
[(eq? pos mouse-over-pos)]
;; mouse on new breakable pos
[(not (eq? (hash-table-get
breakpoints
pos (lambda () 'invalid)) 'invalid))
(set! mouse-over-pos pos)
(invalidate-bitmap-cache)]
;; moved off breakable pos
[mouse-over-pos
(set! mouse-over-pos #f)
(invalidate-bitmap-cache)])
(let* ([frames (send (get-tab) get-stack-frames)]
[pos-vec (send (get-tab) get-pos-vec)]
[id (robust-vector-ref pos-vec pos)])
(send (get-tab)
set-mouse-over-msg
(clean-status
(lookup-var id (list-tail frames (send (get-tab) get-frame-num))
;; id found
(lambda (val _)
(format "~a = ~a" (syntax-e id) (render val)))
;; id not found
(lambda () ""))))))))
(super on-event event)]
[(send event button-down? 'right)
(debugger-handle-right-click event breakpoints)]
[else (super on-event event)])))
(define/override (on-event event)
(if (send (get-tab) debug?)
(let ([breakpoints (send (get-tab) get-breakpoints)])
(cond
[(send event leaving?)
(when mouse-over-pos
(set! mouse-over-pos #f)
(invalidate-bitmap-cache))
(super on-event event)]
[(or (send event moving?)
(send event entering?))
(let-values ([(pos text) (get-pos/text event)])
(when (and pos text)
(let ([pos (add1 pos)])
(cond
; mouse on breakable pos and hasn't moved significantly
[(eq? pos mouse-over-pos)]
; mouse on new breakable pos
[(not (eq? (hash-table-get
breakpoints
pos (lambda () 'invalid)) 'invalid))
(set! mouse-over-pos pos)
(invalidate-bitmap-cache)]
; moved off breakable pos
[mouse-over-pos
(set! mouse-over-pos #f)
(invalidate-bitmap-cache)])
(let* ([frames (send (get-tab) get-stack-frames)]
[pos-vec (send (get-tab) get-pos-vec)]
[id (robust-vector-ref pos-vec pos)]
#;
[_ (printf "frames = ~a~npos-vec = ~a~nid = ~a~n"
frames pos-vec id)])
(send (get-tab)
set-mouse-over-msg
(clean-status
(lookup-var id frames
; id found
(lambda (val _)
(format "~a = ~a" (syntax-e id) (render val)))
; id not found
(lambda () ""))))))))
(super on-event event)]
[(send event button-down? 'right)
(let-values ([(pos text) (get-pos/text event)])
(if (and pos text)
(let* ([pos (add1 pos)]
[break-status (hash-table-get breakpoints pos (lambda () 'invalid))])
(match break-status
[(or #t #f (? procedure?))
(let ([menu (make-object popup-menu% #f)])
(make-object menu-item%
(if break-status
"Remove pause at this point"
"Pause at this point")
menu
(lambda (item evt)
(hash-table-put! breakpoints pos (not break-status))
(invalidate-bitmap-cache)))
(let ([pc (send (get-tab) get-pc)])
(if (and pc (= pos pc))
(let* ([stat (send (get-tab) get-break-status)]
[f (get-top-level-window)]
[rendered-value
(if (cons? stat)
(if (= 2 (length stat))
(render (cadr stat))
(format "~a" (cons 'values
(map (lambda (v) (render v)) (rest stat)))))
"")])
(when (cons? stat)
(make-object menu-item%
"Print return value to console"
menu
(lambda _ (send (get-tab) print-to-console (format "return val = ~a"
rendered-value)))))
(when (not (eq? stat 'break))
(make-object menu-item%
(if (cons? stat)
"Change return value..."
"Skip expression...")
menu
(lambda (item evt)
(let ([tmp (get-text-from-user "Return value" #f)])
(when tmp
(let/ec k
(send (get-tab) set-break-status
(cons 'exit-break
(call-with-values
(lambda ()
(with-handlers
([exn:fail?
(lambda (exn)
(message-box
"Debugger Error"
(format "An error occurred: ~a" (exn-message exn))
#f
'(ok))
(k))])
(read (open-input-string tmp))))
list)))
(invalidate-bitmap-cache))))))))
(make-object menu-item%
"Continue to this point"
menu
(lambda (item evt)
(hash-table-put!
breakpoints pos
(lambda () (hash-table-put! breakpoints pos break-status) #t))
(invalidate-bitmap-cache)
(when (send (get-tab) get-stack-frames)
(send (get-tab) resume))))))
(send (get-canvas) popup-menu menu
(+ 1 (inexact->exact (floor (send event get-x))))
(+ 1 (inexact->exact (floor (send event get-y))))))]
['invalid
(let* ([frames (send (get-tab) get-stack-frames)]
[pos-vec (send (get-tab) get-pos-vec)]
[id (robust-vector-ref pos-vec pos)]
#;
[_ (printf "frames = ~a~npos-vec = ~a~nid = ~a~n"
frames pos-vec id)])
(unless (lookup-var
id
frames
(lambda (val wr)
(let ([id-sym (syntax-e id)]
[menu (make-object popup-menu% #f)])
(make-object menu-item%
(clean-status
(format "Print value of ~a to console" id-sym))
menu
(lambda (item evt)
(send (get-tab) print-to-console (format "~a = ~a" id-sym val))))
(make-object menu-item%
(format "(set! ~a ...)" id-sym)
menu
(lambda (item evt)
(let ([tmp
(get-text-from-user
(format "New value for ~a" id-sym) #f #f
(format "~a" val))])
(when tmp
(let/ec k
(wr (with-handlers
([exn:fail?
(lambda (exn)
(message-box
"Debugger Error"
(format "The following error occurred: ~a"
(exn-message exn)))
(k))])
(read (open-input-string tmp)))))))))
(send (get-canvas) popup-menu menu
(+ 1 (inexact->exact (floor (send event get-x))))
(+ 1 (inexact->exact (floor (send event get-y)))))
#t))
(lambda () #f))
(super on-event event)))]))
(super on-event event)))]
[else (super on-event event)]))
(debugger-handle-event event)
(super on-event event)))
(define/override (on-paint before dc left top right bottom dx dy draw-caret)
(super on-paint before dc left top right bottom dx dy draw-caret)
(when (and (send (get-tab) debug?) (not before))
;; render breakpoints
(let ([breakpoints (send (get-tab) get-breakpoints)])
(hash-table-for-each
breakpoints
@ -449,55 +486,56 @@
(send dc set-brush bp-mo-brush)]
[else (send dc set-pen bp-tmp-pen)
(send dc set-brush bp-tmp-brush)])
;(drscheme:arrow:draw-arrow dc xl yl xr yr dx dy)
(send dc draw-ellipse (+ xl dx) (+ yl dy yoff) diameter diameter)
#;
(send dc draw-polygon stop-sign
(+ xl dx)
(+ yl dy 2))
(send dc set-pen op)
(send dc set-brush ob)))))))
(let ([pc-defs (send (get-tab) defs-containing-pc)]
[pos (send (get-tab) get-pc)])
#;(printf "pc-defs = ~a, this frame = ~a, pos = ~a~n" pc-defs this pos)
(when (and (eq? pc-defs this) pos)
(let*-values ([(xl yl xr yr) (find-char-box this (sub1 pos) pos)]
[(ym) (average yl yr)])
;; mark the boundaries of the current stack frame
;; unless we're at the end of the expression and looking at the top frame,
;; in which case just mark the current location
(let* ([frame-defs (send (get-tab) defs-containing-current-frame)]
[pos (send (get-tab) get-current-frame-endpoints)]
[start (and pos (first pos))]
[end (and pos (second pos))]
[frame-num (send (get-tab) get-frame-num)]
[break-status (send (get-tab) get-break-status)])
(when (and (eq? frame-defs this) start end)
(let*-values ([(xl yl xr yr) (find-char-box this (sub1 start) start)]
[(ym) (average yl yr)]
[(xa ya xb yb) (find-char-box this (sub1 end) end)]
[(diameter) (- xb xa)]
[(yoff) (/ (- yb ya diameter) 2)]
[(ym2) (average ya yb)])
(let ([op (send dc get-pen)]
[ob (send dc get-brush)])
(case (send (get-tab) get-break-status)
[(error) (send dc set-pen pc-err-pen)
(send dc set-brush pc-err-brush)]
[(break) (send dc set-pen pc-brk-pen)
(send dc set-brush pc-brk-brush)]
[else (send dc set-pen pc-pen)
(send dc set-brush pc-brush)]))
(send dc draw-polygon (list (make-object point% xl yl)
(make-object point% xl yr)
(make-object point% xr ym)) dx dy)
#;(drscheme:arrow:draw-arrow dc xl ym xr ym dx dy))
#;
(let loop ([end-pos pos]
[marks (send (get-tab) get-stack-frames)])
(when (cons? marks)
(let*-values ([(start-pos) (syntax-position (mark-source (first marks)))]
[(xl0 yl0 xr0 yr0) (find-char-box this (sub1 start-pos) start-pos)]
[(xm0) (average xl0 xr0)]
[(ym0) (average yl0 yr0)]
[(xl yl xr yr) (find-char-box this (sub1 end-pos) end-pos)]
[(xm) (average xl xr)]
[(ym) (average yl yr)])
(let ([op (send dc get-pen)]
[ob (send dc get-brush)])
(case (send (get-tab) get-break-status)
[(error) (send dc set-pen pc-err-pen)
(send dc set-brush pc-err-brush)]
[(break) (send dc set-pen pc-brk-pen)
(send dc set-brush pc-brk-brush)]
[else (send dc set-pen pc-pen)
(send dc set-brush pc-brush)]))
(drscheme:arrow:draw-arrow dc xm0 ym0 xr ym dx dy)
(loop start-pos (rest marks)))))))))
(cond
[(and (zero? frame-num)
(eq? break-status 'error))
(send dc set-pen pc-err-pen)
(send dc set-brush pc-err-brush)]
[(and (zero? frame-num)
(eq? break-status 'break))
(send dc set-pen pc-brk-pen)
(send dc set-brush pc-brk-brush)]
[(zero? frame-num)
(send dc set-pen pc-pen)
(send dc set-brush pc-brush)]
[else
(send dc set-pen pc-up-stack-pen)
(send dc set-brush pc-up-stack-brush)])
(unless (and (zero? frame-num) (cons? break-status))
;; mark the beginning of the expression with a triangle
(send dc draw-polygon (list (make-object point% xl yl)
(make-object point% xl yr)
(make-object point% xr ym)) dx dy))
(if (and (zero? frame-num) (cons? break-status))
;; top frame, end: mark the end of the expression with a triangle
(send dc draw-polygon (list (make-object point% xa ya)
(make-object point% xa yb)
(make-object point% xb ym2)) dx dy)
;; otherwise: make the end of the expression with a circle
(send dc draw-ellipse (+ xa dx) (+ ya dy yoff) diameter diameter))
(send dc set-pen op)
(send dc set-brush ob)))))))
(define/augment (after-set-next-settings s)
(let ([tlw (get-top-level-window)])
@ -542,8 +580,6 @@
top-e
; annotate-module?
(lambda (fn m)
#;
(printf "debugger: loading ~a (~a)~n" m fn)
(cond
[(filename->defs fn)
=>
@ -551,9 +587,6 @@
(lambda (defs)
(let ([extern-tab (send defs get-tab)]
[this-tab (get-tab)])
; TODO: make sure that defs's tab is
; not already involved in a debugging session
; perhaps allow takeover of previous session
(case (if (or (not (send extern-tab debug?))
(eq? this-tab (send extern-tab get-master)))
(message-box
@ -710,7 +743,7 @@
[slaves empty]
[closed? (box #f)]
[stack-frames (box #f)]
[frame-num 0]
[frame-num (box 0)]
[break-status (box #f)]
[current-language-settings #f]
[pos-vec (vector #f)]
@ -732,18 +765,20 @@
(define/public (get-pos-vec) pos-vec)
(define/public (get-breakpoints) breakpoints)
(define/public (get-break-status) (unbox break-status))
(define/public (get-frame-num) (unbox frame-num))
(define/public (set-shared-data bs sf sema res-ch usr-ch step? m)
(define/public (set-shared-data bs sf sema res-ch usr-ch step? frame m)
(set! break-status bs)
(set! stack-frames sf)
(set! suspend-sema sema)
(set! resume-ch res-ch)
(set! in-user-ch usr-ch)
(set! single-step? step?)
(set! frame-num frame)
(set! master m))
(define/public (get-shared-data)
(values break-status stack-frames suspend-sema resume-ch in-user-ch single-step? master))
(values break-status stack-frames suspend-sema resume-ch in-user-ch single-step? frame-num master))
(define/public (get-single-step-box) single-step?)
(define/public (set-single-step?! v) (set-box! single-step? v))
@ -763,6 +798,14 @@
res) (cdar bindings)]
[else (loop (rest bindings))])))
(define/public (move-up-frame)
(set-box! frame-num (add1 (unbox frame-num)))
(suspend-gui (get-stack-frames) (get-break-status) #t))
(define/public (move-down-frame)
(set-box! frame-num (sub1 (unbox frame-num)))
(suspend-gui (get-stack-frames) (get-break-status) #t))
(define/public (resume)
(let ([v (get-break-status)])
(resume-gui)
@ -780,6 +823,15 @@
(filename->defs source)
(get-defs))))))
(define/public (defs-containing-current-frame)
(let ([stack-frames (get-stack-frames)])
(and (cons? stack-frames)
(let* ([src-stx (mark-source (list-ref stack-frames (get-frame-num)))]
[source (syntax-source src-stx)])
(if source
(filename->defs source)
(get-defs))))))
(define/public (get-pc)
(let ([stack-frames (get-stack-frames)])
(and (cons? stack-frames)
@ -790,6 +842,14 @@
end
start)))))
(define/public (get-current-frame-endpoints)
(let ([stack-frames (get-stack-frames)])
(and (cons? stack-frames)
(let* ([src-stx (mark-source (list-ref stack-frames (get-frame-num)))]
[start (syntax-position src-stx)]
[end (and start (+ start (syntax-span src-stx) -1))])
(list start end)))))
(define (do-in-user-thread thunk)
(if (get-break-status)
(channel-put in-user-ch thunk)
@ -831,67 +891,81 @@
(hash-table-get bps pos 'invalid))))
(define (can-step-over? frames status)
(and (eq? status 'entry-break)
(not (eq? (frame->end-breakpoint-status (first frames)) 'invalid))))
(and (or (not (zero? (get-frame-num))) (eq? status 'entry-break))
(not (eq? (frame->end-breakpoint-status (list-ref frames (get-frame-num))) 'invalid))))
(define (can-step-out? frames status)
(or (and (not (empty? frames))
(ormap (lambda (f) (not (eq? (frame->end-breakpoint-status f) 'invalid)))
(rest frames)))
(begin
#;(printf "cannot step out: stack is ~a~n" frames)
#f)))
(let ([frames (list-tail frames (get-frame-num))])
(and (not (empty? frames))
(ormap (lambda (f) (not (eq? (frame->end-breakpoint-status f) 'invalid)))
(rest frames)))))
(define (can-move-up-frame? frames)
(< (get-frame-num) (sub1 (length frames))))
(define (can-move-down-frame? frames)
(> (get-frame-num) 0))
(define/public suspend-gui
(opt-lambda (frames status [switch-tabs? #f])
(set! want-suspend-on-break? #f)
(set-single-step?! #f)
(set-box! stack-frames frames)
(set-box! break-status status)
(send (send (get-frame) get-pause-button) enable #f)
(send (send (get-frame) get-step-button) enable #t)
(send (send (get-frame) get-step-over-button) enable (can-step-over? frames status))
(send (send (get-frame) get-step-out-button) enable (can-step-out? frames status))
(send (send (get-frame) get-resume-button) enable #t)
;;(fprintf (current-error-port) "break: ~a~n" (map expose-mark frames))
;;(printf "status = ~a~n" status)
(when (cons? status)
(let ([expr (mark-source (first frames))])
(cond
; should succeed unless the user closes a slave tab during debugging
[(filename->defs (syntax-source expr))
=>
(lambda (defs)
(send (send (get-frame) get-status-message) set-label
(clean-status
(format "~a ==> ~a"
(trim-expr-str
(send defs get-text
(sub1 (syntax-position expr))
(+ -1 (syntax-position expr) (syntax-span expr))))
(if (= 2 (length status))
(render (cadr status))
(cons 'values (map (lambda (v) (render v)) (rest status))))))))])))
(cond [(get-pc)
=> (lambda (pc)
(cond [(defs-containing-pc)
=> (lambda (defs)
(cond
[(and switch-tabs? (send defs get-filename))
=>
(lambda (fn)
(handler:edit-file fn))])
(send defs scroll-to-position pc))]))])
(send (get-defs) invalidate-bitmap-cache)))
(let ([top-of-stack? (zero? (get-frame-num))]
[status-message (send (get-frame) get-status-message)])
(set! want-suspend-on-break? #f)
(set-single-step?! #f)
(set-box! stack-frames frames)
(set-box! break-status status)
(send (send (get-frame) get-pause-button) enable #f)
(send (send (get-frame) get-step-button) enable top-of-stack?)
(send (send (get-frame) get-step-over-button) enable (can-step-over? frames status))
(send (send (get-frame) get-step-out-button) enable (can-step-out? frames status))
(send (send (get-frame) get-up-frame-button) enable (can-move-up-frame? frames))
(send (send (get-frame) get-down-frame-button) enable (can-move-down-frame? frames))
(send (send (get-frame) get-resume-button) enable #t)
;;(fprintf (current-error-port) "break: ~a~n" (map expose-mark frames))
;;(printf "status = ~a~n" status)
(send status-message set-label
(if (and (cons? status) top-of-stack?)
(let ([expr (mark-source (first frames))])
(cond
; should succeed unless the user closes a slave tab during debugging
[(filename->defs (syntax-source expr))
=>
(lambda (defs)
(clean-status
(format "~a => ~a"
(if (syntax-position expr)
(trim-expr-str
(send defs get-text
(sub1 (syntax-position expr))
(+ -1 (syntax-position expr) (syntax-span expr))))
"??")
(if (= 2 (length status))
(render (cadr status))
(cons 'values (map (lambda (v) (render v)) (rest status)))))))]))
""))
(cond [(get-current-frame-endpoints)
=> (lambda (start/end)
(cond [(and (first start/end) (defs-containing-current-frame))
=> (lambda (defs)
(cond
[(and switch-tabs? (send defs get-filename))
=>
(lambda (fn)
(handler:edit-file fn))])
(send defs scroll-to-position (first start/end)))]))])
(send (get-defs) invalidate-bitmap-cache))))
(define/public (resume-gui)
(set-box! stack-frames #f)
(set-box! break-status #f)
(set-box! frame-num 0)
(send (send (get-frame) get-pause-button) enable #t)
(send (send (get-frame) get-step-button) enable #f)
(send (send (get-frame) get-step-over-button) enable #f)
(send (send (get-frame) get-step-out-button) enable #f)
(send (send (get-frame) get-resume-button) enable #f)
(send (send (get-frame) get-up-frame-button) enable #f)
(send (send (get-frame) get-down-frame-button) enable #f)
(send (send (get-frame) get-status-message) set-label "")
(send (get-defs) invalidate-bitmap-cache))
@ -1062,7 +1136,7 @@
(define resume-button
(instantiate button% ()
[label ((bitmap-label-maker
"Continue"
"Go"
(build-path (collection-path "gui-debugger" "icons") "resume.png")) this)]
[parent debug-panel]
[callback (lambda (button evt)
@ -1088,7 +1162,8 @@
(define (make-big-step-callback out?)
(lambda (btn evt)
; go through stack frames until it's possible to set a breakpoint at the end
(let* ([frames (send (get-current-tab) get-stack-frames)]
(let* ([frames (list-tail (send (get-current-tab) get-stack-frames)
(send (get-current-tab) get-frame-num))]
[frames (case (send (get-current-tab) get-break-status)
[(entry-break) (if out? (rest frames) frames)]
[else (if out? (rest frames) empty)])]
@ -1141,12 +1216,30 @@
[callback (make-big-step-callback #t)]
[enabled #f]))
(define up-frame-button
(new button%
[label ((bitmap-label-maker
"Up"
(build-path (collection-path "gui-debugger" "icons") "up.png")) this)]
[parent debug-panel]
[callback (lambda (btn evt) (send (get-current-tab) move-up-frame))] [enabled #f]))
(define down-frame-button
(new button%
[label ((bitmap-label-maker
"Down"
(build-path (collection-path "gui-debugger" "icons") "down.png")) this)]
[parent debug-panel]
[callback (lambda (btn evt) (send (get-current-tab) move-down-frame))] [enabled #f]))
(define/public (get-debug-button) debug-button)
(define/public (get-pause-button) pause-button)
(define/public (get-resume-button) resume-button)
(define/public (get-step-button) step-button)
(define/public (get-step-over-button) step-over-button)
(define/public (get-step-out-button) step-out-button)
(define/public (get-up-frame-button) up-frame-button)
(define/public (get-down-frame-button) down-frame-button)
(define/public (get-status-message) status-message)
(define mouse-over-message

View File

@ -517,8 +517,9 @@ a Scheme splice box.
@bold{Tip:} The debugger will not work properly on @onscreen{Untitled}
windows or tabs. To debug a new program, make sure it has been saved
to the file system. For best results, do not change the name of the
file in the middle of a debugging session.
to the file system. Also, changing the name of a file in the middle
of a debugging session will prevent the debugger from working properly
on that file.
Like the @onscreen{Run} button, the @as-index{@onscreen{Debug} button}
runs the program in the definitions window. However, instead of
@ -559,6 +560,15 @@ the @onscreen{Over} button, it sets a one-time breakpoint and
continues execution. In this case, the program stops upon returning
to the context or raising an unhandled exception.}
@item{The @as-index{@onscreen{Up} button} is only enabled when
execution is paused within the context of another expression. It
switches the debugger's view to the outer context.}
@item{The @as-index{@onscreen{Down} button} is only enabled when
execution is paused and the @onscreen{Up} button has been clicked at
least once, so the debugger's view is not at the lowest-level
expression. It moves the view context inward one level.}
}
If the program is running (not paused), then only the @as-index{Pause}
@ -590,7 +600,13 @@ and a one-time breakpoint appears as a yellow circle.
language, then the @italic{first time} it is debugged, breakpoints
will only become available in expressions as they are evaluated.
However, the next time the program is debugged, the debugger will
remember the set of breakable locations from the previous session.}
remember the set of breakable locations from the previous session.
@bold{Tip:} Clicking the @onscreen{Run} button after a debugging
session will cause all breakpoints to disappear from the definitions
window. These breakpoints are not forgotten, and clicking
@onscreen{Debug} again will restore them. However, breakpoints do
@italic{not} persist across restarts of DrScheme.}
@item{If execution is paused at the start of an expression, then
right-clicking or control-clicking (Mac OS X) on the green triangle