1 (defpackage :gtk-doc-introspection
2 #+(or clozure-common-lisp openmcl) (:shadowing-import-from :closer-mop #:defgeneric #:ensure-generic-function #:standard-generic-function)
3 (:use :cl :gtk :gobject :gdk :iter :closer-mop)
4 (:export #:get-gobject-classes
5 #:generate-doc-for-class
6 #:generate-texinfo-for-class
7 #:generate-texinfo-for-package
9 #:generate-texinfo-for-enum
10 #:generate-texinfo-for-packages))
12 (in-package :gtk-doc-introspection)
14 (defun get-gobject-classes (package)
15 (when (symbolp package) (setf package (find-package package)))
16 (unless package (error "Package is NIL"))
17 (iter (for symbol in-package package :external-only t)
18 (for class = (find-class symbol nil))
19 (when (and class (subtypep class 'gobject:g-object))
22 (defun get-enums (package)
23 (when (symbolp package) (setf package (find-package package)))
24 (iter (for (g-type-name type) in-hashtable gobject::*registered-enum-types*)
25 (when (eq (symbol-package type) package)
28 (defun get-flags (package)
29 (when (symbolp package) (setf package (find-package package)))
30 (iter (for (g-type-name type) in-hashtable gobject::*registered-flags-types*)
31 (when (eq (symbol-package type) package)
34 (defvar *doc-packages* nil)
36 (defun generate-texinfo-for-packages (directory packages)
37 (setf packages (mapcar (lambda (x)
42 (ensure-directories-exist directory)
43 (let ((*doc-packages* packages))
44 (iter (for package in packages)
45 (for file-name = (format nil "~A.ref.texi" (string-downcase (package-name package))))
46 (for file-path = (merge-pathnames file-name directory))
47 (generate-texinfo-for-package file-path package))))
49 (defun generate-texinfo-for-package (file package)
50 (when (symbolp package) (setf package (find-package package)))
51 (with-open-file (stream file :direction :output :if-exists :supersede)
52 (let ((classes (sort (copy-list (get-gobject-classes package)) #'string< :key #'class-name))
53 (enums (sort (copy-list (get-enums package)) #'string<))
54 (flags (sort (copy-list (get-flags package)) #'string<)))
55 (format stream "@menu~%")
56 (format stream "* ~A Classes::~%" (string-downcase (package-name package)))
57 (format stream "* ~A Enums::~%" (string-downcase (package-name package)))
58 (format stream "* ~A Flags::~%" (string-downcase (package-name package)))
59 (format stream "@end menu~%~%")
60 (format stream "@node ~A Classes~%" (string-downcase (package-name package)))
61 (format stream "@section ~A Classes~%~%" (string-downcase (package-name package)))
62 (format stream "@menu~%")
63 (iter (for class in classes)
64 (format stream "* ~A::~%" (string-downcase (symbol-name (class-name class)))))
65 (format stream "@end menu~%~%")
66 (format stream "Reference of classes in package ~A~%~%" (package-name package))
67 (iter (for class in classes)
68 (generate-texinfo-for-class class stream)
71 (format stream "@node ~A Enums~%" (string-downcase (package-name package)))
72 (format stream "@section ~A Enums~%~%" (string-downcase (package-name package)))
73 (format stream "@menu~%")
74 (iter (for enum in enums)
75 (format stream "* ~A::~%" (string-downcase (symbol-name enum))))
76 (format stream "@end menu~%~%")
77 (format stream "Reference of enums in package ~A~%~%" (package-name package))
78 (iter (for enum in enums)
79 (generate-texinfo-for-enum enum stream)
82 (format stream "@node ~A Flags~%" (string-downcase (package-name package)))
83 (format stream "@section ~A Flags~%~%" (string-downcase (package-name package)))
84 (format stream "@menu~%")
85 (iter (for flags-type in flags)
86 (format stream "* ~A::~%" (string-downcase (symbol-name flags-type))))
87 (format stream "@end menu~%~%")
88 (format stream "Reference of flags in package ~A~%~%" (package-name package))
89 (iter (for flags-type in flags)
90 (generate-texinfo-for-flags flags-type stream)
95 (defun get-class-signals (class)
96 (when (typep class 'gobject-class)
97 (let* ((g-type-name (gobject::gobject-class-g-type-name class))
98 (signals (type-signals g-type-name :include-inherited nil)))
101 (defun generate-doc-for-signal (signal)
104 (defgeneric texi-ref (object))
106 (defmethod texi-ref ((class class))
107 (symbol-texi-ref (class-name class)))
109 (defun symbol-texi-ref (symbol)
110 (if (member (symbol-package symbol) *doc-packages*)
111 (format nil "@ref{~A}" (string-downcase (symbol-name symbol)))
112 (symbol-texi symbol)))
114 (defun symbol-texi (symbol)
115 (format nil "@code{~A}" (string-downcase (symbol-name symbol))))
117 (defun g-type-texi (type)
119 ((g-type= "gchararray" type) "@code{string}")
120 ((g-type= "GStrv" type) "@code{(list string)}")
121 ((or (g-type= +g-type-int+ type)
122 (g-type= +g-type-int64+ type)
123 (g-type= +g-type-long+ type)) "@code{integer}")
124 ((or (g-type= +g-type-uint+ type)
125 (g-type= +g-type-uint64+ type)
126 (g-type= +g-type-ulong+ type)) "@code{(integer 0)}")
127 ((g-type= +g-type-float+ type) "@code{single-float}")
128 ((g-type= +g-type-double+ type) "@code{double-float}")
129 ((g-type= +g-type-void+ type) "@code{null}")
130 ((g-type= +g-type-param+ type) "@code{class-property-info}")
131 ((g-type= +g-type-string+ type) "@code{string}")
132 ((g-type= +g-type-boolean+ type) "@code{boolean}")
133 ((g-type= +g-type-pointer+ type) "@code{foreign-pointer}")
134 ((and (g-type= (g-type-fundamental type) "GEnum")
135 (gethash (g-type-string type) gobject::*registered-enum-types*))
136 (symbol-texi-ref (gethash (g-type-string type) gobject::*registered-enum-types*)))
137 ((and (g-type= (g-type-fundamental type) "GFlags")
138 (gethash (g-type-string type) gobject::*registered-flags-types*))
139 (symbol-texi-ref (gethash (g-type-string type) gobject::*registered-flags-types*)))
140 ((and (or (g-type= (g-type-fundamental type) "GObject")
141 (g-type= (g-type-fundamental type) "GInterface"))
142 (gethash (g-type-string type) gobject::*registered-object-types*))
143 (symbol-texi-ref (gethash (g-type-string type) gobject::*registered-object-types*)))
144 (t (g-type-string type))))
146 (defun generate-texinfo-for-class (class stream)
147 (when (symbolp class) (setf class (find-class class)))
148 (format stream "@node ~A~%" (string-downcase (symbol-name (class-name class))))
149 (format stream "@subsection ~A~%"(string-downcase (symbol-name (class-name class))))
150 (format stream "@Class ~A~%~%" (string-downcase (symbol-name (class-name class))))
151 (format stream "Superclasses: ~{~A~^, ~}~%~%" (mapcar #'texi-ref (class-direct-superclasses class)))
152 (format stream "Slots:~%")
153 (let ((slots (sort (copy-list (class-direct-slots class)) #'string< :key #'slot-definition-name)))
155 (format stream "None~%~%")
157 (format stream "@itemize~%")
158 (iter (for slot in slots)
159 (generate-texinfo-for-slot class slot stream))
160 (format stream "@end itemize~%"))))
161 (format stream "Signals:~%")
162 (let ((signals (sort (copy-list (get-class-signals class)) #'string< :key #'signal-info-name)))
164 (format stream "None~%~%")
166 (format stream "@itemize~%")
167 (iter (for signal in signals)
168 (generate-texinfo-for-signal class signal stream))
169 (format stream "@end itemize~%")))))
171 (defun generate-texinfo-for-slot (class slot stream)
172 (format stream "@item ~A" (string-downcase (slot-definition-name slot)))
174 (when (typep slot 'gobject::gobject-property-direct-slot-definition)
175 (let* ((class-g-type (gobject::gobject-class-g-type-name class))
176 (property-name (gobject::gobject-property-direct-slot-definition-g-property-name slot))
177 (property (if (g-type= (g-type-fundamental class-g-type) "GInterface")
178 (find property-name (interface-properties class-g-type)
179 :key #'g-class-property-definition-name
181 (class-property-info class-g-type property-name))))
182 (format stream ". Type: ~A (flags:~@[~* readable~]~@[~* writable~]~@[~* constructor~]~@[~* constructor-only~])~%~%"
183 (g-type-texi (g-class-property-definition-type property))
184 (g-class-property-definition-readable property)
185 (g-class-property-definition-writable property)
186 (g-class-property-definition-constructor property)
187 (g-class-property-definition-constructor-only property)))))
188 (format stream "~%~%"))
190 (defun generate-texinfo-for-signal (class signal stream)
191 (declare (ignore class))
192 (format stream "@item ~A. (~{~A~^, ~}) -> ~A ~@[ [~{~A~^, ~}]~]~%~%"
193 (signal-info-name signal)
194 (mapcar #'g-type-texi (signal-info-param-types signal))
195 (g-type-texi (signal-info-return-type signal))
196 (mapcar (lambda (x) (string-downcase (symbol-name x)))
197 (signal-info-flags signal))))
199 (defun generate-texinfo-for-enum (enum stream)
200 (format stream "@node ~A~%" (string-downcase enum))
201 (format stream "@subsection ~A~%" (string-downcase enum))
202 (format stream "@Enum ~A~%" (string-downcase enum))
203 (format stream "Values:~%")
204 (format stream "@itemize~%")
205 (iter (for v in (cffi::foreign-enum-keyword-list enum))
206 (format stream "@item ~A~%" (string-downcase (format nil "~S" v))))
207 (format stream "@end itemize~%~%"))
209 (defun generate-texinfo-for-flags (flags stream)
210 (format stream "@node ~A~%" (string-downcase flags))
211 (format stream "@subsection ~A~%" (string-downcase flags))
212 (format stream "@Flags ~A~%" (string-downcase flags))
213 (format stream "Values:~%")
214 (format stream "@itemize~%")
215 (iter (for v in (cffi::foreign-bitfield-symbol-list flags))
216 (format stream "@item ~A~%" (string-downcase (format nil "~S" v))))
217 (format stream "@end itemize~%~%"))