+
+;; Enum skeleton
+;; (enum-skeleton enum &key (section "section"))
+;; @node $enum
+;; @section $enum
+;; Values:
+;; @itemize
+;; $(enum-values enum)
+;; @end itemize
+
+(defun enum-skeleton (enum &key (section "section"))
+ (with-output-to-string (stream)
+ (format stream "@node ~A~%" (string-downcase enum))
+ (format stream "@~A ~A~%" section (string-downcase enum))
+ (format stream "@Enum ~A~%" (string-downcase enum))
+ (format stream "Values: ~%")
+ (format stream "@itemize~%")
+ (iter (for item in (cffi:foreign-enum-keyword-list enum))
+ (format stream "@item :~A~%" (string-downcase (symbol-name item))))
+ (format stream "@end itemize~%")))
+
+(defun flags-skeleton (flags &key (section "section"))
+ (with-output-to-string (stream)
+ (format stream "@node ~A~%" (string-downcase flags))
+ (format stream "@~A ~A~%" section (string-downcase flags))
+ (format stream "@Flags ~A~%" (string-downcase flags))
+ (format stream "Values: ~%")
+ (format stream "@itemize~%")
+ (iter (for item in (cffi:foreign-bitfield-symbol-list flags))
+ (format stream "@item :~A~%" (string-downcase (symbol-name item))))
+ (format stream "@end itemize~%")))
+
+(defun all-enums (package)
+ (sort (iter (for symbol in-package package :external-only t)
+ (when (ignore-errors (cffi:foreign-enum-keyword-list symbol))
+ (collect symbol)))
+ #'string<))
+
+(defun all-flags (package)
+ (sort (iter (for symbol in-package package :external-only t)
+ (when (ignore-errors (cffi:foreign-bitfield-symbol-list symbol))
+ (collect symbol)))
+ #'string<))
+
+(defun enum-chapter-skeleton (output enums &key (section "section"))
+ (cond
+ ((or (pathnamep output) (stringp output))
+ (with-open-file (stream output :direction :output :if-exists :supersede)
+ (enum-chapter-skeleton stream enums :section section)))
+ ((null output) (with-output-to-string (stream)
+ (enum-chapter-skeleton stream enums :section section)))
+ ((or (eq t output) (streamp output))
+ (format output "@menu~%")
+ (iter (for e in enums)
+ (format output "* ~A::~%" (string-downcase (symbol-name e))))
+ (format output "@end menu~%~%")
+ (iter (for e in enums)
+ (write-string (enum-skeleton e :section section) output)
+ (format output "~%~%")))))
+
+(defun flags-chapter-skeleton (output flagss &key (section "section"))
+ (cond
+ ((or (pathnamep output) (stringp output))
+ (with-open-file (stream output :direction :output :if-exists :supersede)
+ (flags-chapter-skeleton stream flagss :section section)))
+ ((null output) (with-output-to-string (stream)
+ (flags-chapter-skeleton stream flagss :section section)))
+ ((or (eq t output) (streamp output))
+ (format output "@menu~%")
+ (iter (for e in flagss)
+ (format output "* ~A::~%" (string-downcase (symbol-name e))))
+ (format output "@end menu~%~%")
+ (iter (for e in flagss)
+ (write-string (flags-skeleton e :section section) output)
+ (format output "~%~%")))))
+
+;; Struct skeleton
+;; (struct-skeleton struct &key (section "section") (use-refs t))
+;; @node $struct
+;; @$section $struct
+;; @Struct @struct
+;; Slots:
+;; @itemize
+;; $(for each slot
+;; @item $slot
+;; )
+;; @end itemize
+
+(defun struct-skeleton (struct &key (section "section") (use-refs t))
+ (unless (typep struct 'class) (setf struct (find-class struct)))
+ (with-output-to-string (stream)
+ (let ((*print-case* :downcase)
+ (*package* (symbol-package (class-name struct)))
+ (*print-circle* nil)
+ (*use-refs* use-refs))
+ (format stream "@node ~A~%" (class-name struct))
+ (format stream "@~A ~A~%" section (class-name struct))
+ (format stream "@Struct ~A~%" (class-name struct))
+ (format stream "Superclass:")
+ (iter (for super in (class-direct-superclasses struct))
+ (format stream " ~A" (format-ref (class-name super))))
+ (when (class-direct-subclasses struct)
+ (format stream "~%~%")
+ (format stream "Subclasses:")
+ (iter (for sub in (class-direct-subclasses struct))
+ (format stream " ~A" (format-ref (class-name sub)))))
+ (format stream "~%~%")
+ (struct-slots stream struct))))
+
+(defun struct-slots (stream struct)
+ (format stream "Slots:~%")
+ (format stream "@itemize~%")
+ (iter (for slot in (class-direct-slots struct))
+ (format stream "@item @anchor{slot.~A.~A}~A. Accessor: ~A."
+ (class-name struct) (string-downcase (slot-definition-name slot))
+ (string-downcase (slot-definition-name slot))
+ (format nil "~A-~A" (class-name struct) (slot-definition-name slot)))
+ (format stream "~%"))
+ (format stream "@end itemize~%"))
+
+(defun all-structs (package)
+ (sort (iter (for symbol in-package package :external-only t)
+ (for class = (find-class symbol nil))
+ (when (and class (typep class (find-class 'structure-class)))
+ (collect symbol)))
+ #'string<))
+
+(defun struct-chapter-skeleton (output structs &key (section "section") (use-refs t))
+ (cond
+ ((or (stringp output) (pathnamep output))
+ (with-open-file (stream output :direction :output :if-exists :supersede)
+ (struct-chapter-skeleton stream structs :section section :use-refs use-refs)))
+ ((null output) (with-output-to-string (stream)
+ (struct-chapter-skeleton stream structs :section section :use-refs use-refs)))
+ ((or (eq t output) (streamp output))
+ (format output "@menu~%")
+ (iter (for e in structs)
+ (format output "* ~A::~%" (string-downcase (symbol-name e))))
+ (format output "@end menu~%~%")
+ (iter (for e in structs)
+ (write-string (struct-skeleton e :section section :use-refs use-refs) output)
+ (format output "~%~%")))))
+
+(defun interface-chapter-skeleton (output interfaces &key (use-refs t) (section "section"))
+ (cond
+ ((or (stringp output) (pathnamep output))
+ (with-open-file (stream output :direction :output :if-exists :supersede)
+ (interface-chapter-skeleton stream interfaces :use-refs use-refs :section section)))
+ ((null output) (with-output-to-string (stream)
+ (interface-chapter-skeleton stream interfaces :use-refs use-refs :section section)))
+ ((or (eq t output) (streamp output))
+ (format output "@menu~%")
+ (iter (for w in interfaces)
+ (format output "* ~A::~%" (string-downcase (symbol-name w))))
+ (format output "@end menu~%~%")
+ (iter (for w in interfaces)
+ (write-string (interface-skeleton w :section section :use-refs use-refs) output)
+ (format output "~%~%")))))
+
+(defun all-interfaces (package)
+ (sort (iter (for symbol in-package package :external-only t)
+ (for class = (find-class symbol nil))
+ (when (and class
+ (typep class 'gobject:gobject-class)
+ (gobject::gobject-class-interface-p class))
+ (collect symbol)))
+ #'string<))
+
+;; (interface-skeleton interface &key (sectioning-command "section"))
+;; returns the texinfo string for interface (a symbol or class)
+;; Template:
+;;
+;; @node $INTERFACE
+;; @$SECTIONING-COMMAND $INTERFACE
+;;
+;; @Class $INTERFACE
+;;
+;; Interfaces: $(direct-interface interface)
+;;
+;; Slots:
+;; @itemize
+;; $(for each slot)
+;; @item @anchor{slot.$interface.$slot}$slot. Type: $(slot-type slot). Accessor: $(slot-accessor slot). $(when (constructor-only slot) "Contructor-only slot.")
+;; $(end for)
+;; @end itemize
+;;
+;; Signals:
+;; @itemize
+;; $(for each signal)
+;; @item @anchor{signal.$interface.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
+;; $(end for)
+;; @end itemize
+
+(defun interface-skeleton (interface &key (section "section") (use-refs t))
+ (unless (typep interface 'class) (setf interface (find-class interface)))
+ (with-output-to-string (stream)
+ (let ((*print-case* :downcase)
+ (*package* (symbol-package (class-name interface)))
+ (*print-circle* nil)
+ (*use-refs* use-refs))
+ (format stream "@node ~A~%" (class-name interface))
+ (format stream "@~A ~A~%" section (class-name interface))
+ (format stream "@Class ~A~%" (class-name interface))
+ (format stream "~%~%")
+ (widget-slots stream interface)
+ (format stream "~%~%")
+ (widget-signals stream interface))))
+
+(defun all-gtk-skeletons (dir)
+ (widgets-chapter-skeleton (merge-pathnames "gdk.objects.texi" dir) (all-classes (find-package :gdk)))
+ (widgets-chapter-skeleton (merge-pathnames "gtk.objects.texi" dir) (all-classes (find-package :gtk)))
+ (struct-chapter-skeleton (merge-pathnames "gtk.structs.texi" dir) (all-structs (find-package :gtk)))
+ (struct-chapter-skeleton (merge-pathnames "gdk.structs.texi" dir) (all-structs (find-package :gdk)))
+ (widgets-chapter-skeleton (merge-pathnames "gtk.widgets.texi" dir) (all-widgets (find-package :gtk)))
+ (interface-chapter-skeleton (merge-pathnames "gtk.interfaces.texi" dir) (all-interfaces (find-package :gtk)))
+ (enum-chapter-skeleton (merge-pathnames "gtk.enums.texi" dir) (all-enums :gtk))
+ (enum-chapter-skeleton (merge-pathnames "gdk.enums.texi" dir) (all-enums :gdk))
+ (flags-chapter-skeleton (merge-pathnames "gtk.flags.texi" dir) (all-flags :gtk))
+ (flags-chapter-skeleton (merge-pathnames "gdk.flags.texi" dir) (all-flags :gdk)))
\ No newline at end of file