marketplace-2014/marketplace/support/gui.rkt

268 lines
7.4 KiB
Racket

#lang racket/base
(require racket/set)
(require racket/match)
(require racket/class)
(require racket/async-channel)
(require racket/gui/base)
(require racket/date)
(require racket/format)
(require racket/math)
(require images/icons/control)
(require images/icons/arrow)
(require images/icons/symbol)
(require images/icons/misc)
(require images/icons/style)
(require racket/pretty)
(require (prefix-in core: "../types.rkt"))
(provide any-state?
open-debugger)
;; Frame
;; Toolbar
;; Rewind one step - moves without executing
;; Fast-forward one step - moves without executing
;; --
;; Stop
;; Run one step
;; Play
;; --
;; Select history depth
;; --
;; Kill this process
;; State display
;; If the state is (vm?), special display; permits spawning debuggers on nested processes
;; Endpoints display
;; Shows ID and role
;; Permits deletion of endpoint
;; Permits interaction with endpoint??
;; Trace display
;; Selection of a row rewinds to that point
(define (any-state? x) #t)
(define (open-debugger name)
(define to-debugger (make-channel))
(define from-debugger (make-semaphore 0))
(parameterize ((current-eventspace (make-eventspace)))
(new debugger%
[name name]
[from-vm to-debugger]
[to-vm from-debugger]))
(values (lambda (t) (channel-put to-debugger t))
(lambda () (semaphore-wait from-debugger))))
(define debugger%
(class object%
(init-field name)
(init-field from-vm)
(init-field to-vm)
(define mutex (make-semaphore 1))
(define stepping? #t)
(define waiting? #f)
(define frame (new frame%
[label (format "~a" name)]
[width 480]
[height 700]))
(define menu-bar (new menu-bar% [parent frame]))
(define edit-menu (new menu% [label "Edit"] [parent menu-bar]))
(append-editor-operation-menu-items edit-menu #f)
(define toolbar (new horizontal-pane%
[parent frame]
[stretchable-height #f]
[alignment '(right center)]))
(define state-panel (new horizontal-panel%
[parent frame]))
(define endpoints (new list-box%
[style '(single column-headers)]
[label #f]
[choices '()]
[parent frame]
[columns '("ID" "Orientation" "Topic" "Type")]))
(define events (new list-box%
[style '(single column-headers)]
[label #f]
[choices '()]
[parent frame]
[columns '("Time" "Dir" "Type" "Detail")]))
(send endpoints set-column-width 1 32 32 32)
(send endpoints set-column-width 3 32 32 32)
(send events set-column-width 1 32 32 32)
(define (toolbar-button label [handler void])
(new button%
[label label]
[min-width 32]
[parent toolbar]
[callback handler]))
(define (toolbar-spacer)
(new pane% [parent toolbar] [min-width 16] [stretchable-width #f]))
;; (toolbar-button (left-over-arrow-icon #:color syntax-icon-color))
;; (toolbar-button (right-over-arrow-icon #:color syntax-icon-color))
;; (toolbar-spacer)
(define pause-button
(toolbar-button (pause-icon #:color halt-icon-color)
(lambda (b e)
(send pause-button enable #f)
(send play-button enable #t)
(send step-button enable #t)
(call-with-semaphore
mutex
(lambda ()
(set! stepping? #f))))))
(define play-button
(toolbar-button (play-icon #:color run-icon-color)
(lambda (b e)
(send pause-button enable #t)
(send play-button enable #f)
(send step-button enable #f)
(call-with-semaphore
mutex
(lambda ()
(set! stepping? #t)
(when waiting?
(set! waiting? #f)
(semaphore-post to-vm)))))))
(toolbar-spacer)
(define step-button
(toolbar-button (step-icon #:color run-icon-color)
(lambda (b e)
(call-with-semaphore
mutex
(lambda ()
(when waiting?
(set! waiting? #f)
(semaphore-post to-vm)))))))
(send play-button enable #f)
(send step-button enable #f)
;; (toolbar-spacer)
;; (toolbar-button "Settings...")
;; (toolbar-spacer)
;; (toolbar-button (stop-sign-icon))
(define state-text (new text%))
(define state-canvas (new editor-canvas%
[parent state-panel]
[editor state-text]
[label "State"]))
(define controller-thread
(thread
(lambda ()
(controller-thread-loop))))
(define (current-timestamp)
(define (p n w) (~a (exact-truncate n) #:width w #:align 'right #:pad-string "0"))
(define d (current-date))
(format "~a:~a:~a.~a ~a-~a-~a"
(p (date-hour d) 2)
(p (date-minute d) 2)
(p (date-second d) 2)
(p (/ (date*-nanosecond d) 1000000.0) 3)
(date-year d)
(p (date-month d) 2)
(p (date-day d) 2)))
(define (record-event! stamp dir type detail)
(define n (send events get-number))
(send events append stamp)
(send events set-string n dir 1)
(send events set-string n type 2)
(send events set-string n (~a detail) 3)
(send events set-first-visible-item
(max 0 (- n (- (send events number-of-visible-items) 1)))))
(define (format-action action)
(cond
[(core:yield? action)
(values "Yield" "")]
[(core:at-meta-level? action)
(format-preaction "Meta" (core:at-meta-level-preaction action))]
[else
(format-preaction "" action)]))
(define (format-preaction layer preaction)
(define-values (type detail)
(match preaction
[(core:add-endpoint pre-eid role handler)
(values "Sub" (string-append (format-role role) " " (~a pre-eid)))]
[(core:delete-endpoint pre-eid reason)
(values "Unsub" (format "~a ~v" pre-eid reason))]
[(core:send-message body 'publisher)
(values "Send" (~v body))]
[(core:send-message body 'subscriber)
(values "Feedback" (~v body))]
[(core:spawn spec maybe-k child-debug-name)
(values "Spawn" (~v child-debug-name))]
[(core:quit #f reason)
(values "Exit" (~v reason))]
[(core:quit pid reason)
(values "Kill" (format "~a ~v" pid reason))]))
(values (string-append layer type) detail))
(define (format-role r)
(match-define (core:role orientation topic interest-type) r)
(format "~a/~a ~v"
(string-ref (symbol->string orientation) 0)
(string-ref (symbol->string interest-type) 0)
topic))
(define (handle-from-vm x)
(define now (current-timestamp))
(match x
[(core:transition state actions)
(send state-text erase)
(send state-text insert (pretty-format state))
(let loop ((a actions))
(cond
[(pair? a) (loop (car a)) (loop (cdr a))]
[(or (null? a) (eq? a #f) (void? a)) (void)]
[else (define-values (type detail) (format-action a))
(record-event! now "Act" type detail)]))
(call-with-semaphore
mutex
(lambda ()
(if stepping?
(semaphore-post to-vm)
(set! waiting? #t))))]
[(cons meta? e)
(define prefix (if meta? "Meta" ""))
(match e
[(core:presence-event role)
(record-event! now "Evt" (string-append prefix "Presence") (format-role role))]
[(core:absence-event role reason)
(record-event! now "Evt" (string-append prefix "Absence")
(string-append (format-role role) " " (~v reason)))]
[(core:message-event _ message)
(record-event! now "Evt" (string-append prefix "Recv") (~v message))])]))
(define (controller-thread-loop)
(sync (handle-evt from-vm
(lambda (x)
(handle-from-vm x)
(controller-thread-loop)))))
(super-new)
(send frame show #t)
))