#! /bin/sh
exec guile -L . -e main -s "$0" "$@"
!#
(use-modules (rnrs bytevectors)
(ice-9 binary-ports)
(ice-9 format)
(srfi srfi-26)
(srfi srfi-43)
(scmvm vm)
(oop goops)
(g-golf))
(eval-when (expand load eval)
(g-irepository-require "Gtk" #:version "4.0")
(gi-import-by-name "Gdk" "keyval_name")
(for-each (lambda (name)
(gi-import-by-name "Gio" name))
'("SimpleAction"
"SimpleActionGroup"))
(for-each (lambda (name) (gi-import-by-name "Gtk" name))
'("Application"
"ApplicationWindow"
"Box"
"Button"
"CallbackAction"
"CssProvider"
"EventControllerKey"
"FileDialog"
"Frame"
"Label")))
(define *css* "
.mono {
font-family: monospace;
}")
(define-syntax-rule (named-lambda lambda-name args body ...)
(lambda args #((name . lambda-name)) body ...))
(define %vm (make-vm #:memory-size 100))
(define %program #f)
(define %buffer-label #f)
(define %selected-byte 0)
(define (load-binary port)
(set! %program port))
(define (update-memory-view!)
(when %buffer-label
(define ram (vm-memory %vm))
(define text
(vector-fold
(lambda (i s byte)
(string-append
s
(if (and (is-focus (get-parent %buffer-label)) (= %selected-byte i))
(format #f "~:@(~2'0x~) " byte)
(format #f "~:@(~2'0x~) " byte))))
""
ram))
(set-markup %buffer-label text)))
(define (open-file win cb)
(define dialog (make ))
(define (cb-with-port dialog result data)
(call-with-input-file (get-path (open-finish dialog result)) cb))
(open dialog win #f cb-with-port #f))
(define (install-action action-group name callback)
(define action (make #:name name))
(add-action action-group action)
(connect action 'activate (lambda (a v) (callback))))
(define (activate app)
(newline)
;; Setup window
(define win (make
#:application app
#:title "Scheme Compiler"))
(define css-provider (make ))
(load-from-string css-provider *css*)
(gtk-style-context-add-provider-for-display
(gdk-display-get-default) css-provider #xffff)
(define box (make
#:orientation 'vertical
#:focusable #t))
(set-child win box)
;; Setup menu
(let ([app-action-group (make )]
[menu (make )]
[file-menu (make )])
(append file-menu "Open..." "app.open-file")
(append-submenu menu "File" file-menu)
(set-menubar app menu)
(set-show-menubar win #t)
(insert-action-group win "app" app-action-group)
(install-action
app-action-group
"open-file"
(lambda () (open-file win load-binary))))
;; Setup buffer view
(set! %buffer-label (make
#:css-classes '("mono")
#:wrap #t
#:focusable #t))
(set-can-focus %buffer-label #t)
(set! %selected-byte 0)
(define frame (make
#:focusable #t))
(define buffer-controller (make ))
(gtk-widget-add-controller frame buffer-controller)
(connect buffer-controller 'key-pressed handle-key-event)
(set-child frame %buffer-label)
(append box frame)
(update-memory-view!)
;(connect win 'move-focus move-focus) ; TODO needs some sort of return value
(append box (make ))
(append box (make ))
;; Present window
(present win))
(define (move-focus . args)
(update-memory-view!)
#t)
(define (handle-key-event e val code mod)
(if
(case (string->symbol (gdk-keyval-name val))
[(Left) (set! %selected-byte (max (1- %selected-byte) 0)) #t]
[(Right) (set! %selected-byte (min (1+ %selected-byte) 99)) #t]
[else #f])
(begin (update-memory-view!) #t)
#f))
(define* (main #:optional args)
(define app (make ))
(connect app 'activate activate)
(let ([status (run app args)])
(exit status)))
;;; DEBUG
(use-modules (ice-9 threads))
(define (debug)
(define app (make ))
(connect app 'activate activate)
(begin-thread
(run app '())))
;; Local Variables:
;; mode: scheme
;; End: