chiark / gitweb /
Display Lisp implementation in main window
[clg] / examples / ginspect.lisp
CommitLineData
a9d159ba 1(in-package :gtk)
2
3(defgeneric insert-object (object store parent &optional prefix))
4(defgeneric insert-parts (object store parent))
5(defgeneric object-hash-parts-p (object))
6
7
8(defun ginspect (object)
9 (let* ((store (make-instance 'tree-store
10 :column-types '(string string gobject boolean)
11 :column-names '(prefix pprint object expanded)))
12 (view (make-instance 'tree-view :model store :headers-visible nil)))
13
14 (let ((column (make-instance 'tree-view-column))
15 (prefix (make-instance 'cell-renderer-text))
16 (object (make-instance 'cell-renderer-text)))
17 (cell-layout-pack column prefix :expand nil)
18 (cell-layout-add-attribute column prefix 'text 0)
19 (cell-layout-pack column object :expand t)
20 (cell-layout-add-attribute column object 'text 1)
21 (tree-view-append-column view column))
22
23 (insert-object object store nil)
24
25 (signal-connect view 'row-expanded
26 #'(lambda (iter path)
27 (unless (tree-model-column-value store iter 'expanded)
28 (multiple-value-bind (valid dummy)
29 (tree-model-iter-children store iter)
30 ;; Remove dummy child
31 (when valid
32 (tree-store-remove store dummy)))
33 (let ((gobject (tree-model-column-value store iter 'object)))
34 (insert-parts (object-data gobject 'object) store iter))
35 (setf (tree-model-column-value store iter 'expanded) t)
36 (tree-view-expand-row view path nil))))
37
38 (make-instance 'dialog
39 :title "Object Inspector" :show-all t
40 :default-width 600 :default-height 600
41 :button (list "gtk-close" #'widget-destroy :object t)
42 :child (make-instance 'scrolled-window
43 :hscrollbar-policy :automatic :child view))))
44
45
46(defun object-to-string (object)
47 (with-output-to-string (stream)
48 (write object :stream stream :lines 1 :right-margin 80)))
49
50(defmethod insert-object ((object t) store parent &optional (prefix ""))
51 (let ((gobject (make-instance 'gobject)) ; to "hang" the lisp object on
52 (has-parts (object-has-parts-p object)))
53 (setf (object-data gobject 'object) object)
54 (let ((iter (tree-store-append store parent
55 (vector prefix (object-to-string object)
56 gobject (not has-parts)))))
57 (when has-parts
58 ;; Insert dummy child
59 (tree-store-append store iter (vector "" "" gobject t))))))
60
61(defmethod object-has-parts-p ((object t))
62 (declare (ignore object))
63 t)
64
65(defmethod insert-parts ((object t) store parent)
66 (let ((parts (nth-value 1 (swank-backend:inspected-parts object))))
67 (unless (and (endp (rest parts)) (eq object (cdar parts)))
68 (loop
69 for (prefix . part) in parts
70 do (insert-object part store parent prefix)))))
71
72(defun propper-list-p (object)
73 (and (listp object) (null (cdr (last object)))))
74
75(defmethod insert-parts ((object cons) store parent)
76 (if (propper-list-p object)
77 (loop
78 for element in object
79 do (insert-object element store parent))
80 (progn
81 (insert-object (car object) store parent)
82 (insert-object (cdr object) store parent))))
83
84(defmethod insert-parts ((object vector) store parent)
85 (loop
86 for element across object
87 do (insert-object element store parent)))
88
89(defmethod insert-parts ((object (eql t)) store parent)
90 (declare (ignore object store parent)))
91
92(defmethod object-has-parts-p ((object (eql t)))
93 (declare (ignore object))
94 nil)
95
96(defmethod insert-parts ((object (eql nil)) store parent)
97 (declare (ignore object store parent)))
98
99(defmethod object-has-parts-p ((object (eql nil)))
100 (declare (ignore object))
101 nil)
102
103(defvar *unbound-object-marker* (gensym "UNBOUND-OBJECT-"))
104
105(defmethod insert-parts ((object symbol) store parent)
106 (insert-object
107 (if (boundp object)
108 (symbol-value object)
109 *unbound-object-marker*)
110 store parent "Value")
111 (insert-object
112 (if (fboundp object)
113 (symbol-function object)
114 *unbound-object-marker*)
115 store parent "Function")
116 (insert-object (symbol-plist object) store parent "Plist")
117 (insert-object (symbol-package object) store parent "Package"))
118
119
120(defmethod insert-parts ((object standard-object) store parent)
121 (loop
122 for slotd in (class-slots (class-of object))
123 do (let* ((slot-name (slot-value slotd 'pcl::name))
124 (slot-value (if (slot-boundp object slot-name)
125 (slot-value object slot-name)
126 *unbound-object-marker*)))
127 (insert-object slot-value store parent (string slot-name)))))
128
129(defmethod insert-object ((object (eql *unbound-object-marker*))
130 store parent &optional prefix)
131 (tree-store-append store parent (vector prefix "<unbound>" (make-instance 'gobject) t nil)))
132
133(defmethod insert-parts ((object (eql *unbound-object-marker*)) store parent)
134 (declare (ignore object store parent)))
135
136(defmethod object-has-parts-p ((object character))
137 (declare (ignore object))
138 nil)
139
140(defmethod object-has-parts-p ((object number))
141 (declare (ignore object))
142 nil)
143
144(defmethod object-has-parts-p ((object alien:system-area-pointer))
145 (declare (ignore object))
146 nil)