(defpackage :clos-browser (:use :clim-lisp :clim) (:export #:main)) (in-package :clos-browser) (define-application-frame class-browser () ((classes :initarg :classes :reader classes) (visible-classes :initform nil :accessor visible-classes) (current-class :initform nil :accessor current-class)) (:panes (classes :application :incremental-redisplay t :display-function 'display-classes :double-buffering t) (methods :application :incremental-redisplay t :display-function 'display-current-class :scroll-bars :both) (int :interactor :scroll-bars :both)) (:pointer-documentation t) (:layouts (default (vertically () (horizontally () classes methods) int)) (maximize-int (vertically () int))) (:default-initargs :classes (let ((classes ())) (do-all-symbols (s (sort (remove-duplicates classes) #'string< :key #'class-name)) (alexandria:when-let ((class (find-class s nil))) (push class classes)))))) (defun reset-application-frame () (setf (visible-classes clim:*application-frame*) nil (current-class clim:*application-frame*) nil (slot-value clim:*application-frame* 'classes) (let ((classes ())) (do-all-symbols (s (sort (remove-duplicates classes) #'string< :key #'class-name)) (alexandria:when-let ((class (find-class s nil))) (push class classes)))))) (define-presentation-type clos-class ()) (define-presentation-method present (object (type clos-class) stream view &key) (declare (ignore view)) (format stream "#" (class-name object))) (defun display-classes (frame pane) (updating-output (pane :unique-id (or (visible-classes frame) (classes frame)) :id-test 'eq) (loop for class in (or (visible-classes frame) (classes frame)) do (updating-output (pane :unique-id (sxhash class) :id-test 'eql :cache-value class :cache-test 'eql) (with-output-as-presentation (pane class 'clos-class) (format pane "~&~a~%" (class-name class))))))) (defun display-current-class (frame pane) (updating-output (pane :unique-id (current-class frame) :id-test 'eq) (when (current-class frame) (format-graph-from-roots (list (current-class frame)) (lambda (c stream) (present c 'clos-class :stream stream)) (lambda (c) (closer-mop:class-direct-superclasses c)) :stream pane :duplicate-test 'eq :graph-type :dag :orientation :vertical :merge-duplicates t :arc-drawer (lambda (stream foo bar x1 y1 x2 y2) (updating-output (pane :unique-id (list foo bar) :id-test 'equal) (draw-arrow* stream x1 y1 x2 y2 :ink (make-contrasting-inks 1 0)))))))) (define-class-browser-command (com-pick-class :name t :menu t) ((the-class clos-class :gesture :select)) (setf (current-class *application-frame*) the-class)) (define-class-browser-command (com-current-class :name t) () (let ((current-class (current-class clim:*application-frame*))) (with-output-as-presentation (*query-io* current-class 'clos-class :single-box t) (format t "~&#~%" (class-name current-class))))) (define-class-browser-command (com-refresh-classes :name t :menu t) () (reset-application-frame)) (define-class-browser-command (com-filter-classes :name t :menu t) ((pattern string)) (let ((scanner (cl-ppcre:create-scanner pattern :case-insensitive-mode t))) (setf (visible-classes *application-frame*) (remove-if-not (lambda (_) (cl-ppcre:scan scanner (princ-to-string _))) (classes *application-frame*) :key 'class-name)))) (define-class-browser-command (com-show-hierarchy :name t) ((the-class clos-class)) (format-graph-from-roots (list the-class) (lambda (c stream) (present c 'clos-class :stream stream)) (lambda (c) (closer-mop:class-direct-superclasses c)) :stream *query-io* :duplicate-test 'eq :graph-type :tree :merge-duplicates t :arc-drawer (lambda (stream foo bar x1 y1 x2 y2) (declare (ignore foo bar)) (draw-arrow* stream x1 y1 x2 y2 :ink (make-contrasting-inks 1 0))))) (define-class-browser-command (com-show-subclasses :name t) ((the-class clos-class)) (format-graph-from-roots (list the-class) (lambda (c stream) (present c 'clos-class :stream stream)) (lambda (c) (closer-mop:class-direct-subclasses c)) :stream *query-io* :duplicate-test 'eq :graph-type :tree :merge-duplicates t :arc-drawer (lambda (stream foo bar x1 y1 x2 y2) (declare (ignore foo bar)) (draw-arrow* stream x1 y1 x2 y2 :ink (make-contrasting-inks 1 0))))) (define-class-browser-command (com-maximize-int :name t) () (let ((old-view (clim:frame-current-layout clim:*application-frame*))) (setf (clim:frame-current-layout clim:*application-frame*) (case old-view ('default 'maximize-int) (t 'default))))) (define-class-browser-command (com-exit :name "Quit" :command-table application-commands :menu t :provide-output-destination-keyword nil) () (frame-exit *application-frame*)) (defvar *proc*) (defun %main () (clim:run-frame-top-level (clim:make-application-frame 'class-browser))) (defun main () (setf *proc* (bt:make-thread (lambda () (%main)))))