git.fiddlerwoaroof.com
Browse code

Simple CLIM browser for CLOS classes

Ed Langley authored on 28/01/2019 11:03:05
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,157 @@
1
+(defpackage :clos-browser
2
+  (:use :clim-lisp :clim)
3
+  (:export
4
+   #:main))
5
+(in-package :clos-browser)
6
+
7
+(define-application-frame class-browser ()
8
+  ((classes :initarg :classes :reader classes)
9
+   (visible-classes :initform nil :accessor visible-classes)
10
+   (current-class :initform nil :accessor current-class))
11
+  (:panes (classes :application
12
+                   :incremental-redisplay t
13
+                   :display-function 'display-classes
14
+                   :double-buffering t)
15
+          (methods :application
16
+                   :incremental-redisplay t
17
+                   :display-function 'display-current-class
18
+                   :scroll-bars :both)
19
+          (int :interactor
20
+               :scroll-bars :both))
21
+  (:pointer-documentation t)
22
+  (:layouts (default (vertically ()
23
+                       (horizontally ()
24
+                         classes methods)
25
+                       int))
26
+            (maximize-int (vertically ()
27
+                            int)))
28
+  (:default-initargs
29
+      :classes (let ((classes ()))
30
+                 (do-all-symbols (s (sort (remove-duplicates classes)
31
+                                          #'string<
32
+                                          :key #'class-name))
33
+                   (alexandria:when-let ((class (find-class s nil)))
34
+                     (push class classes))))))
35
+
36
+(defun reset-application-frame ()
37
+  (setf (visible-classes clim:*application-frame*) nil
38
+        (current-class clim:*application-frame*) nil
39
+        (slot-value clim:*application-frame* 'classes)
40
+        (let ((classes ()))
41
+          (do-all-symbols (s (sort (remove-duplicates classes)
42
+                                   #'string<
43
+                                   :key #'class-name))
44
+            (alexandria:when-let ((class (find-class s nil)))
45
+              (push class classes))))))
46
+
47
+(define-presentation-type clos-class ())
48
+(define-presentation-method present (object (type clos-class) stream view &key)
49
+  (declare (ignore view))
50
+  (format stream "#<CLOS Class: ~a>"
51
+          (class-name object)))
52
+
53
+(defun display-classes (frame pane)
54
+  (updating-output (pane :unique-id (or (visible-classes frame)
55
+                                        (classes frame))
56
+                         :id-test 'eq)
57
+    (loop for class in (or (visible-classes frame)
58
+                           (classes frame))
59
+       do (updating-output (pane :unique-id (sxhash class)
60
+                                 :id-test 'eql
61
+                                 :cache-value class
62
+                                 :cache-test 'eql)
63
+            (with-output-as-presentation (pane class 'clos-class)
64
+              (format pane "~&~a~%" (class-name class)))))))
65
+
66
+(defun display-current-class (frame pane)
67
+  (updating-output (pane :unique-id (current-class frame)
68
+                         :id-test 'eq)
69
+    (when (current-class frame)
70
+      (format-graph-from-roots (list (current-class frame))
71
+                               (lambda (c stream)
72
+                                 (present c 'clos-class :stream stream))
73
+                               (lambda (c)
74
+                                 (closer-mop:class-direct-superclasses c))
75
+                               :stream pane
76
+                               :duplicate-test 'eq
77
+                               :graph-type :dag
78
+                               :orientation :vertical
79
+                               :merge-duplicates t
80
+                               :arc-drawer (lambda (stream foo bar x1 y1 x2 y2)
81
+                                             (updating-output (pane :unique-id (list foo bar)
82
+                                                                    :id-test 'equal)
83
+                                               (draw-arrow* stream x1 y1 x2 y2
84
+                                                            :ink (make-contrasting-inks 1 0))))))))
85
+
86
+(define-class-browser-command (com-pick-class :name t :menu t) ((the-class clos-class :gesture :select))
87
+  (setf (current-class *application-frame*) the-class))
88
+
89
+(define-class-browser-command (com-current-class :name t) ()
90
+  (let ((current-class (current-class clim:*application-frame*)))
91
+    (with-output-as-presentation (*query-io* current-class 'clos-class :single-box t)
92
+      (format t "~&#<CLOS Class: ~s>~%" (class-name current-class)))))
93
+
94
+
95
+(define-class-browser-command (com-refresh-classes :name t :menu t) ()
96
+  (reset-application-frame))
97
+
98
+(define-class-browser-command (com-filter-classes :name t :menu t) ((pattern string))
99
+  (let ((scanner (cl-ppcre:create-scanner pattern :case-insensitive-mode t)))
100
+    (setf (visible-classes *application-frame*)
101
+          (remove-if-not (lambda (_)
102
+                           (cl-ppcre:scan scanner
103
+                                          (princ-to-string _)))
104
+                         (classes *application-frame*)
105
+                         :key 'class-name))))
106
+
107
+(define-class-browser-command (com-show-hierarchy :name t) ((the-class clos-class))
108
+  (format-graph-from-roots (list the-class)
109
+                           (lambda (c stream)
110
+                             (present c 'clos-class :stream stream))
111
+                           (lambda (c)
112
+                             (closer-mop:class-direct-superclasses c))
113
+                           :stream *query-io*
114
+                           :duplicate-test 'eq
115
+                           :graph-type :tree
116
+                           :merge-duplicates t
117
+                           :arc-drawer (lambda (stream foo bar x1 y1 x2 y2)
118
+                                         (declare (ignore foo bar))
119
+                                         (draw-arrow* stream x1 y1 x2 y2
120
+                                                      :ink (make-contrasting-inks 1 0)))))
121
+
122
+(define-class-browser-command (com-show-subclasses :name t) ((the-class clos-class))
123
+  (format-graph-from-roots (list the-class)
124
+                           (lambda (c stream)
125
+                             (present c 'clos-class :stream stream))
126
+                           (lambda (c)
127
+                             (closer-mop:class-direct-subclasses c))
128
+                           :stream *query-io*
129
+                           :duplicate-test 'eq
130
+                           :graph-type :tree
131
+                           :merge-duplicates t
132
+                           :arc-drawer (lambda (stream foo bar x1 y1 x2 y2)
133
+                                         (declare (ignore foo bar))
134
+                                         (draw-arrow* stream x1 y1 x2 y2
135
+                                                      :ink (make-contrasting-inks 1 0)))))
136
+
137
+(define-class-browser-command (com-maximize-int :name t) ()
138
+  (let ((old-view (clim:frame-current-layout clim:*application-frame*)))
139
+    (setf (clim:frame-current-layout clim:*application-frame*)
140
+          (case old-view
141
+            ('default  'maximize-int)
142
+            (t 'default)))))
143
+
144
+(define-class-browser-command (com-exit :name "Quit"
145
+			                                  :command-table application-commands
146
+                                        :menu t
147
+			                                  :provide-output-destination-keyword nil)
148
+    ()
149
+  (frame-exit *application-frame*))
150
+
151
+(defvar *proc*)
152
+(defun %main ()
153
+  (clim:run-frame-top-level
154
+   (clim:make-application-frame 'class-browser)))
155
+
156
+(defun main ()
157
+  (setf *proc* (bt:make-thread (lambda () (%main)))))