Added documentation skeleton and merged skeleton with exisiting docs
[cl-gtk2.git] / doc / skeleton.lisp
1 (defpackage :doc-skeleton
2   (:use :cl :gtk :gdk :gobject :iter :c2mop :glib)
3   (:export :widget-skeleton
4            :widgets-chapter-skeleton
5            :*gtk-widgets*
6            :all-gtk-widgets
7            :enum-skeleton
8            :flags-skeleton
9            :all-enums
10            :all-flags
11            :enum-chapter-skeleton
12            :flags-chapter-skeleton
13            :struct-skeleton
14            #:all-structs
15            #:struct-chapter-skeleton
16            #:interface-chapter-skeleton
17            #:all-interfaces
18            #:interface-skeleton
19            #:all-widgets
20            #:all-classes
21            #:all-gtk-skeletons))
22
23 (in-package :doc-skeleton)
24
25 (defun widgets-chapter-skeleton (output widgets &key (use-refs t) (section "section"))
26   (cond
27     ((or (pathnamep output)
28          (stringp output))
29      (with-open-file (stream output :direction :output :if-exists :supersede)
30        (widgets-chapter-skeleton stream widgets :use-refs use-refs :section section)))
31     ((null output) (with-output-to-string (stream)
32                      (widgets-chapter-skeleton stream widgets :use-refs use-refs :section section)))
33     ((or (eq t output) (streamp output))
34      (format output "@menu~%")
35      (iter (for w in widgets)
36            (format output "* ~A::~%" (string-downcase (symbol-name w))))
37      (format output "@end menu~%~%")
38      (iter (for w in widgets)
39            (write-string (widget-skeleton w :section section :use-refs use-refs) output)
40            (format output "~%~%")))))
41
42 (defparameter *gtk-widgets* '(about-dialog accel-label alignment arrow
43   aspect-frame assistant bin box button button-box calendar cell-view
44   check-button check-menu-item color-button color-selection
45   color-selection-dialog combo-box combo-box-entry container curve
46   dialog drawing-area entry event-box expander file-chooser-button
47   file-chooser-dialog file-chooser-widget fixed font-button
48   font-selection font-selection-dialog frame gamma-curve gtk-window
49   h-box h-button-box h-paned h-ruler h-s-v h-scale h-scrollbar
50   h-separator handle-box icon-view image image-menu-item input-dialog
51   invisible item label layout link-button menu menu-bar menu-item
52   menu-shell menu-tool-button message-dialog misc notebook
53   old-editable paned plug progress progress-bar radio-button
54   radio-menu-item radio-tool-button range recent-chooser-dialog
55   recent-chooser-menu recent-chooser-widget ruler scale scale-button
56   scrollbar scrolled-window separator separator-menu-item
57   separator-tool-item socket spin-button statusbar table
58   tearoff-menu-item text text-view toggle-button toggle-tool-button
59   tool-button tool-item toolbar tree tree-item tree-view v-box
60   v-button-box v-paned v-ruler v-scale v-scrollbar v-separator
61   viewport volume-button widget))
62
63 (defun all-gtk-widgets ()
64   (all-widgets (find-package :gtk)))
65
66 (defun all-widgets (package)
67   (sort (iter (for symbol in-package (find-package package) :external-only t)
68               (for class = (find-class symbol nil))
69               (when (and class (subclassp class (find-class 'gtk:widget)))
70                 (collect symbol)))
71         #'string<))
72
73 (defun all-classes (package)
74   (sort (iter (for symbol in-package (find-package package) :external-only t)
75               (for class = (find-class symbol nil))
76               (when (and class
77                          (not (subclassp class (find-class 'condition)))
78                          (not (subclassp class (find-class 'gtk:widget)))
79                          (or (not (typep class 'gobject::gobject-class))
80                              (not (gobject::gobject-class-interface-p class)))
81                          (not (typep class 'structure-class)))
82                 (collect symbol)))
83         #'string<))
84
85 ;; (widget-skeleton widget &key (sectioning-command "section"))
86 ;; returns the texinfo string for widget (a symbol or class)
87 ;; Template:
88 ;; 
89 ;; @node $WIDGET
90 ;; @$SECTIONING-COMMAND $WIDGET
91 ;;
92 ;; @Class $WIDGET
93 ;; 
94 ;; Superclass: $(direct-superclass WIDGET)
95 ;;
96 ;; Interfaces: $(direct-interface widget)
97 ;;
98 ;; Slots:
99 ;; @itemize
100 ;; $(for each slot)
101 ;; @item @anchor{slot.$widget.$slot}$slot. Type: $(slot-type slot). Accessor: $(slot-accessor slot). $(when (constructor-only slot) "Contructor-only slot.")
102 ;; $(end for)
103 ;; @end itemize
104 ;;
105 ;; Signals:
106 ;; @itemize
107 ;; $(for each signal)
108 ;; @item @anchor{signal.$widget.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
109 ;; $(end for)
110 ;; @end itemize
111
112 (defvar *use-refs* t)
113
114 (defun widget-skeleton (widget &key (section "section") (use-refs t))
115   (unless (typep widget 'class) (setf widget (find-class widget)))
116   (with-output-to-string (stream)
117     (let ((*print-case* :downcase)
118           (*package* (symbol-package (class-name widget)))
119           (*print-circle* nil)
120           (*use-refs* use-refs))
121       (format stream "@node ~A~%" (class-name widget))
122       (format stream "@~A ~A~%" section (class-name widget))
123       (format stream "@Class ~A~%" (class-name widget))
124       (format stream "Superclass:")
125       (iter (for super in (class-direct-superclasses widget))
126             (unless (and (typep super 'gobject-class) (gobject::gobject-class-interface-p super))
127               (format stream " ~A" (format-ref (class-name super)))))
128       (when (class-direct-subclasses widget)
129         (format stream "~%~%")
130         (format stream "Subclasses:")
131         (iter (for sub in (class-direct-subclasses widget))
132               (format stream " ~A" (format-ref (class-name sub)))))
133       (format stream "~%~%")
134       (widget-slots stream widget)
135       (format stream "~%~%")
136       (widget-signals stream widget)
137       (format stream "~%~%")
138       (widget-child-properties stream widget))))
139
140 (defun widget-slots (stream widget)
141   (format stream "Slots:~%")
142   (format stream "@itemize~%")
143   (iter (for slot in (class-direct-slots widget))
144         (when (typep slot 'gobject::gobject-direct-slot-definition)
145           (format stream "@item @anchor{slot.~A.~A}~A. Type: ~A. Accessor: ~A."
146                   (class-name widget) (slot-definition-name slot)
147                   (slot-definition-name slot)
148                   (slot-type slot)
149                   (slot-accessor slot))
150           (case (classify-slot-readability widget slot)
151             (:write-only (format stream " Write-only."))
152             (:read-only (format stream " Read-only.")))
153           (format stream "~%")))
154   (format stream "@end itemize~%"))
155
156 (defun widget-signals (stream widget)
157   (when (typep widget 'gobject::gobject-class)
158     (let ((g-type (gobject::gobject-class-direct-g-type-name widget)))
159       (when g-type
160         (format stream "Signals:~%")
161         (format stream "@itemize~%")
162         ;; @item @anchor{signal.$widget.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
163         (iter (for signal in (type-signals g-type))
164               (format stream "@item @anchor{signal.~A.~A}\"~A\". Signature: ~A. Options: ~A."
165                       (class-name widget)
166                       (signal-info-name signal)
167                       (signal-info-name signal)
168                       (signal-signature signal)
169                       (signal-options signal))
170               (format stream "~%"))
171         (format stream "@end itemize~%")))))
172
173 (defun widget-child-properties (stream widget)
174   (when (typep stream 'gobject::gobject-class)
175     (let ((g-type (gobject::gobject-class-g-type-name widget)))
176       (when (g-type-is-a g-type "GtkContainer")
177         (unless (string= g-type (gobject::gobject-class-g-type-name (first (class-direct-superclasses widget))))
178           (let ((props (gtk::container-class-child-properties g-type)))
179             (when props
180               (format stream "Child properties:~%")
181               (format stream "@itemize~%")
182               ;; @item @anchor{signal.$widget.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
183               (iter (for prop in props)
184                     (for accessor = (format nil "~A-child-~A"
185                                             (string-downcase (symbol-name (class-name widget)))
186                                             (g-class-property-definition-name prop)))
187                     (format stream "@item @anchor{childprop.~A.~A}~A. Type: ~A. Accessor: ~A."
188                             (string-downcase (symbol-name (class-name widget)))
189                             (g-class-property-definition-name prop)
190                             (g-class-property-definition-name prop)
191                             (type-string (g-class-property-definition-type prop))
192                             accessor)
193                     (format stream "~%"))
194               (format stream "@end itemize~%"))))))))
195
196 (defun signal-signature (s)
197   (with-output-to-string (stream)
198     (format stream "(instance ~A)" (type-string (signal-info-owner-type s)))
199     (iter (for type in (signal-info-param-types s))
200           (for counter from 1)
201           (format stream ", (arg-~A ~A)" counter (type-string type)))
202     (format stream " @result{} ~A" (type-string (signal-info-return-type s)))))
203
204 (defun signal-options (s)
205   (format nil "~{~A~^, ~}"(signal-info-flags s)))
206
207 (defun slot-type (slot)
208   (let ((type (gobject::gobject-direct-slot-definition-g-property-type slot)))
209     (type-string type)))
210
211 (defun type-string (type)
212   (typecase type
213     (string (type-string-s type))
214     (t (type-string-f type))))
215
216 (defun ensure-list (x) (if (listp x) x (list x)))
217
218 (defun type-string-f (type)
219   (let ((l (ensure-list type)))
220     (case (first l)
221       ((:string glib:g-string) "@code{string}")
222       ((:int :uint :long :ulong :char :uchar :int64 :uint64) "@code{integer}")
223       ((:boolean :bool) "@code{boolean}")
224       (g-object (if (second l)
225                     (format-ref (second l))
226                     "@ref{g-object}"))
227       (g-boxed-foreign (format-ref (second l)))
228       ((nil) "????")
229       ((glist gslist) (format nil "list of ~A" (type-string-f (second l))))
230       (t (if (symbolp type)
231              (format-ref type)
232              (format-ref l))))))
233
234 (defun type-string-s (type)
235   (cond
236     ((g-type= type +g-type-string+) "@code{string}")
237     ((g-type= type +g-type-boolean+) "@code{boolean}")
238     ((g-type= type +g-type-float+) "@code{single-float}")
239     ((g-type= type +g-type-double+) "@code{double-float}")
240     ((or (g-type= type +g-type-int+)
241          (g-type= type +g-type-uint+)
242          (g-type= type +g-type-char+)
243          (g-type= type +g-type-uchar+)
244          (g-type= type +g-type-long+)
245          (g-type= type +g-type-ulong+)
246          (g-type= type +g-type-int64+)
247          (g-type= type +g-type-uint64+)
248          (g-type= type +g-type-uint64+)) "@code{integer}")
249     ((g-type= type +g-type-float+) "@code{single-float}")
250     ((g-type-is-a type +g-type-enum+) (enum-string type))
251     ((g-type-is-a type +g-type-flags+) (flags-string type))
252     ((g-type-is-a type +g-type-object+) (object-string type))
253     ((g-type-is-a type +g-type-boxed+) (boxed-string type))
254     (t type)))
255
256 (defun format-ref (s)
257   (if (and *use-refs* (if (symbolp s)
258                           (not (eq (symbol-package s) (find-package :cl)))
259                           t))
260       (format nil "@ref{~A}" s)
261       (format nil "@code{~A}" s)))
262
263 (defun flags-string (type)
264   (let ((flags (gobject::registered-flags-type (g-type-string type))))
265     (if flags
266         (format-ref flags)
267         (format nil "@code{~A}" (g-type-string type)))))
268
269 (defun enum-string (type)
270   (let ((enum (gobject::registered-enum-type (g-type-string type))))
271     (if enum
272         (format-ref enum)
273         (format nil "@code{~A}" (g-type-string type)))))
274
275 (defun object-string (type)
276   (let ((class (gobject::registered-object-type-by-name (g-type-string type))))
277     (if class
278         (format-ref class)
279         (format nil "@code{~A}" (g-type-string type)))))
280
281 (defun boxed-string (type)
282   (let ((boxed (ignore-errors (gobject::get-g-boxed-foreign-info-for-gtype (g-type-string type)))))
283     (if boxed
284         (format-ref (gobject::g-boxed-info-name boxed))
285         (format nil "@code{~A}" (g-type-string type)))))
286
287 (defmethod classify-slot-readability (class (slot gobject::gobject-property-direct-slot-definition))
288   (let* ((g-type (gobject::gobject-class-g-type-name class))
289          (property-name (gobject::gobject-property-direct-slot-definition-g-property-name slot))
290          (prop (if (g-type-is-a g-type +g-type-interface+)
291                    (find property-name (interface-properties g-type)
292                          :test #'string=
293                          :key #'g-class-property-definition-name)
294                    (class-property-info g-type property-name)))
295          (readable (g-class-property-definition-readable prop))
296          (writable (g-class-property-definition-writable prop)))
297     (cond
298       ((and readable writable) :normal)
299       ((not readable) :write-only)
300       ((not writable) :read-only)
301       (t :bad))))
302
303 (defmethod classify-slot-readability (class (slot gobject::gobject-fn-direct-slot-definition))
304   (let ((readable (gobject::gobject-fn-direct-slot-definition-g-getter-name slot))
305         (writable (gobject::gobject-fn-direct-slot-definition-g-setter-name slot)))
306     (cond
307       ((and readable writable) :normal)
308       ((not readable) :write-only)
309       ((not writable) :read-only)
310       (t :bad))))
311
312 (defun slot-accessor (slot)
313   (let* ((readers (slot-definition-readers slot))
314          (writers (mapcar #'second (slot-definition-writers slot)))
315          (combined (union readers writers))
316          (accessor (first combined)))
317     (if accessor
318         (format nil "@anchor{fn.~A}@code{~A}" accessor accessor)
319         (format nil "None"))))
320
321 ;; Enum skeleton
322 ;; (enum-skeleton enum &key (section "section"))
323 ;; @node $enum
324 ;; @section $enum
325 ;; Values:
326 ;; @itemize
327 ;; $(enum-values enum)
328 ;; @end itemize
329
330 (defun enum-skeleton (enum &key (section "section"))
331   (with-output-to-string (stream)
332     (format stream "@node ~A~%" (string-downcase enum))
333     (format stream "@~A ~A~%" section (string-downcase enum))
334     (format stream "@Enum ~A~%" (string-downcase enum))
335     (format stream "Values: ~%")
336     (format stream "@itemize~%")
337     (iter (for item in (cffi:foreign-enum-keyword-list enum))
338           (format stream "@item :~A~%" (string-downcase (symbol-name item))))
339     (format stream "@end itemize~%")))
340
341 (defun flags-skeleton (flags &key (section "section"))
342   (with-output-to-string (stream)
343     (format stream "@node ~A~%" (string-downcase flags))
344     (format stream "@~A ~A~%" section (string-downcase flags))
345     (format stream "@Flags ~A~%" (string-downcase flags))
346     (format stream "Values: ~%")
347     (format stream "@itemize~%")
348     (iter (for item in (cffi:foreign-bitfield-symbol-list flags))
349           (format stream "@item :~A~%" (string-downcase (symbol-name item))))
350     (format stream "@end itemize~%")))
351
352 (defun all-enums (package)
353   (sort (iter (for symbol in-package package :external-only t)
354               (when (ignore-errors (cffi:foreign-enum-keyword-list symbol))
355                 (collect symbol)))
356         #'string<))
357
358 (defun all-flags (package)
359   (sort (iter (for symbol in-package package :external-only t)
360               (when (ignore-errors (cffi:foreign-bitfield-symbol-list symbol))
361                 (collect symbol)))
362         #'string<))
363
364 (defun enum-chapter-skeleton (output enums &key (section "section"))
365   (cond
366     ((or (pathnamep output) (stringp output))
367      (with-open-file (stream output :direction :output :if-exists :supersede)
368        (enum-chapter-skeleton stream enums :section section)))
369     ((null output) (with-output-to-string (stream)
370                      (enum-chapter-skeleton stream enums :section section)))
371     ((or (eq t output) (streamp output))
372      (format output "@menu~%")
373      (iter (for e in enums)
374            (format output "* ~A::~%" (string-downcase (symbol-name e))))
375      (format output "@end menu~%~%")
376      (iter (for e in enums)
377            (write-string (enum-skeleton e :section section) output)
378            (format output "~%~%")))))
379
380 (defun flags-chapter-skeleton (output flagss &key (section "section"))
381   (cond
382     ((or (pathnamep output) (stringp output))
383      (with-open-file (stream output :direction :output :if-exists :supersede)
384        (flags-chapter-skeleton stream flagss :section section)))
385     ((null output) (with-output-to-string (stream)
386                      (flags-chapter-skeleton stream flagss :section section)))
387     ((or (eq t output) (streamp output))
388      (format output "@menu~%")
389      (iter (for e in flagss)
390            (format output "* ~A::~%" (string-downcase (symbol-name e))))
391      (format output "@end menu~%~%")
392      (iter (for e in flagss)
393            (write-string (flags-skeleton e :section section) output)
394            (format output "~%~%")))))
395
396 ;; Struct skeleton
397 ;; (struct-skeleton struct &key (section "section") (use-refs t))
398 ;; @node $struct
399 ;; @$section $struct
400 ;; @Struct @struct
401 ;; Slots:
402 ;; @itemize
403 ;; $(for each slot
404 ;; @item $slot
405 ;; )
406 ;; @end itemize
407
408 (defun struct-skeleton (struct &key (section "section") (use-refs t))
409   (unless (typep struct 'class) (setf struct (find-class struct)))
410   (with-output-to-string (stream)
411     (let ((*print-case* :downcase)
412           (*package* (symbol-package (class-name struct)))
413           (*print-circle* nil)
414           (*use-refs* use-refs))
415       (format stream "@node ~A~%" (class-name struct))
416       (format stream "@~A ~A~%" section (class-name struct))
417       (format stream "@Struct ~A~%" (class-name struct))
418       (format stream "Superclass:")
419       (iter (for super in (class-direct-superclasses struct))
420             (format stream " ~A" (format-ref (class-name super))))
421       (when (class-direct-subclasses struct)
422         (format stream "~%~%")
423         (format stream "Subclasses:")
424         (iter (for sub in (class-direct-subclasses struct))
425               (format stream " ~A" (format-ref (class-name sub)))))
426       (format stream "~%~%")
427       (struct-slots stream struct))))
428
429 (defun struct-slots (stream struct)
430   (format stream "Slots:~%")
431   (format stream "@itemize~%")
432   (iter (for slot in (class-direct-slots struct))
433         (format stream "@item @anchor{slot.~A.~A}~A. Accessor: ~A."
434                 (class-name struct) (string-downcase (slot-definition-name slot))
435                 (string-downcase (slot-definition-name slot))
436                 (format nil "~A-~A" (class-name struct) (slot-definition-name slot)))
437         (format stream "~%"))
438   (format stream "@end itemize~%"))
439
440 (defun all-structs (package)
441   (sort (iter (for symbol in-package package :external-only t)
442               (for class = (find-class symbol nil))
443               (when (and class (typep class (find-class 'structure-class)))
444                 (collect symbol)))
445         #'string<))
446
447 (defun struct-chapter-skeleton (output structs &key (section "section") (use-refs t))
448   (cond
449     ((or (stringp output) (pathnamep output))
450      (with-open-file (stream output :direction :output :if-exists :supersede)
451        (struct-chapter-skeleton stream structs :section section :use-refs use-refs)))
452     ((null output) (with-output-to-string (stream)
453                      (struct-chapter-skeleton stream structs :section section :use-refs use-refs)))
454     ((or (eq t output) (streamp output))
455      (format output "@menu~%")
456      (iter (for e in structs)
457            (format output "* ~A::~%" (string-downcase (symbol-name e))))
458      (format output "@end menu~%~%")
459      (iter (for e in structs)
460            (write-string (struct-skeleton e :section section :use-refs use-refs) output)
461            (format output "~%~%")))))
462
463 (defun interface-chapter-skeleton (output interfaces &key (use-refs t) (section "section"))
464   (cond
465     ((or (stringp output) (pathnamep output))
466      (with-open-file (stream output :direction :output :if-exists :supersede)
467        (interface-chapter-skeleton stream interfaces :use-refs use-refs :section section)))
468     ((null output) (with-output-to-string (stream)
469                      (interface-chapter-skeleton stream interfaces :use-refs use-refs :section section)))
470     ((or (eq t output) (streamp output))
471      (format output "@menu~%")
472      (iter (for w in interfaces)
473            (format output "* ~A::~%" (string-downcase (symbol-name w))))
474      (format output "@end menu~%~%")
475      (iter (for w in interfaces)
476            (write-string (interface-skeleton w :section section :use-refs use-refs) output)
477            (format output "~%~%")))))
478
479 (defun all-interfaces (package)
480   (sort (iter (for symbol in-package package :external-only t)
481               (for class = (find-class symbol nil))
482               (when (and class
483                          (typep class 'gobject:gobject-class)
484                          (gobject::gobject-class-interface-p class))
485                 (collect symbol)))
486         #'string<))
487
488 ;; (interface-skeleton interface &key (sectioning-command "section"))
489 ;; returns the texinfo string for interface (a symbol or class)
490 ;; Template:
491 ;; 
492 ;; @node $INTERFACE
493 ;; @$SECTIONING-COMMAND $INTERFACE
494 ;;
495 ;; @Class $INTERFACE
496 ;; 
497 ;; Interfaces: $(direct-interface interface)
498 ;;
499 ;; Slots:
500 ;; @itemize
501 ;; $(for each slot)
502 ;; @item @anchor{slot.$interface.$slot}$slot. Type: $(slot-type slot). Accessor: $(slot-accessor slot). $(when (constructor-only slot) "Contructor-only slot.")
503 ;; $(end for)
504 ;; @end itemize
505 ;;
506 ;; Signals:
507 ;; @itemize
508 ;; $(for each signal)
509 ;; @item @anchor{signal.$interface.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
510 ;; $(end for)
511 ;; @end itemize
512
513 (defun interface-skeleton (interface &key (section "section") (use-refs t))
514   (unless (typep interface 'class) (setf interface (find-class interface)))
515   (with-output-to-string (stream)
516     (let ((*print-case* :downcase)
517           (*package* (symbol-package (class-name interface)))
518           (*print-circle* nil)
519           (*use-refs* use-refs))
520       (format stream "@node ~A~%" (class-name interface))
521       (format stream "@~A ~A~%" section (class-name interface))
522       (format stream "@Class ~A~%" (class-name interface))
523       (format stream "~%~%")
524       (widget-slots stream interface)
525       (format stream "~%~%")
526       (widget-signals stream interface))))
527
528 (defun all-gtk-skeletons (dir)
529   (widgets-chapter-skeleton (merge-pathnames "gdk.objects.texi" dir) (all-classes (find-package :gdk)))
530   (widgets-chapter-skeleton (merge-pathnames "gtk.objects.texi" dir) (all-classes (find-package :gtk)))
531   (struct-chapter-skeleton (merge-pathnames "gtk.structs.texi" dir) (all-structs (find-package :gtk)))
532   (struct-chapter-skeleton (merge-pathnames "gdk.structs.texi" dir) (all-structs (find-package :gdk)))
533   (widgets-chapter-skeleton (merge-pathnames "gtk.widgets.texi" dir) (all-widgets (find-package :gtk)))
534   (interface-chapter-skeleton (merge-pathnames "gtk.interfaces.texi" dir) (all-interfaces (find-package :gtk)))
535   (enum-chapter-skeleton (merge-pathnames "gtk.enums.texi" dir) (all-enums :gtk))
536   (enum-chapter-skeleton (merge-pathnames "gdk.enums.texi" dir) (all-enums :gdk))
537   (flags-chapter-skeleton (merge-pathnames "gtk.flags.texi" dir) (all-flags :gtk))
538   (flags-chapter-skeleton (merge-pathnames "gdk.flags.texi" dir) (all-flags :gdk)))