]> code.delx.au - gnu-emacs-elpa/blob - gnome-c-snippet.el
snippet: Add missing GObjectClass vfunc
[gnu-emacs-elpa] / gnome-c-snippet.el
1 ;;; gnome-c-snippet.el --- GNOME-style code generation -*- lexical-binding: t; -*-
2 ;; Copyright (C) 2016 Free Software Foundation, Inc.
3
4 ;; Author: Daiki Ueno <ueno@gnu.org>
5 ;; Keywords: GNOME, C, coding style
6
7 ;; This file is not part of GNU Emacs.
8
9 ;; This program is free software: you can redistribute it and/or
10 ;; modify it under the terms of the GNU General Public License as
11 ;; published by the Free Software Foundation, either version 3 of the
12 ;; License, or (at your option) any later version.
13
14 ;; This program is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ;; General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program. If not, see
21 ;; <http://www.gnu.org/licenses/>.
22
23 ;;; Code:
24
25 (require 'gnome-c-align)
26
27 (eval-when-compile
28 (require 'subword))
29
30 (declare-function subword-forward "subword.el" (&optional arg))
31
32 (defvar gnome-c-snippet-package nil)
33 (make-variable-buffer-local 'gnome-c-snippet-package)
34
35 (defvar gnome-c-snippet-class nil)
36 (make-variable-buffer-local 'gnome-c-snippet-class)
37
38 (defvar gnome-c-snippet-parent-package nil)
39 (make-variable-buffer-local 'gnome-c-snippet-parent-package)
40
41 (defvar gnome-c-snippet-parent-class nil)
42 (make-variable-buffer-local 'gnome-c-snippet-parent-class)
43
44 (defcustom gnome-c-snippet-align-arglist t
45 "Whether to align argument list of the inserted snippet"
46 :type 'boolean
47 :group 'gnome-c-style)
48
49 (make-variable-buffer-local 'gnome-c-snippet-align-arglist)
50
51 (defun gnome-c-snippet--parse-name (name)
52 (require 'subword)
53 (with-temp-buffer
54 (let (words)
55 (insert name)
56 (goto-char (point-min))
57 (while (not (eobp))
58 ;; Skip characters not recognized by subword-mode.
59 (if (looking-at "[^[:lower:][:upper:][:digit:]]+")
60 (goto-char (match-end 0)))
61 (push (buffer-substring (point) (progn (subword-forward 1)
62 (point)))
63 words))
64 (nreverse words))))
65
66 (defun gnome-c-snippet--read-package-and-class (package-prompt
67 class-prompt
68 package-symbol
69 class-symbol)
70 (when (or current-prefix-arg
71 (not (and (symbol-value package-symbol)
72 (symbol-value class-symbol))))
73 (set package-symbol
74 (gnome-c-snippet--parse-name
75 (read-string (or package-prompt
76 "Package (CamelCase): ")
77 (if (symbol-value package-symbol)
78 (gnome-c-snippet--format-Package
79 (symbol-value package-symbol))))))
80 (set class-symbol
81 (gnome-c-snippet--parse-name
82 (read-string (or class-prompt
83 "Class (CamelCase): ")
84 (if (symbol-value class-symbol)
85 (gnome-c-snippet--format-Class
86 (symbol-value class-symbol)))))))
87 (list (symbol-value package-symbol) (symbol-value class-symbol)))
88
89 (defun gnome-c-snippet--format-PACKAGE (package)
90 (mapconcat #'upcase package "_"))
91 (defalias 'gnome-c-snippet--format-CLASS 'gnome-c-snippet--format-PACKAGE)
92
93 (defun gnome-c-snippet--format-PACKAGE_CLASS (package class)
94 (concat (gnome-c-snippet--format-PACKAGE package)
95 "_"
96 (gnome-c-snippet--format-CLASS class)))
97
98 (defun gnome-c-snippet--format-package (package)
99 (mapconcat #'downcase package "_"))
100 (defalias 'gnome-c-snippet--format-class 'gnome-c-snippet--format-package)
101
102 (defun gnome-c-snippet--format-package_class (package class)
103 (concat (gnome-c-snippet--format-package package)
104 "_"
105 (gnome-c-snippet--format-class class)))
106
107 (defun gnome-c-snippet--format-Package (package)
108 (mapconcat #'identity package ""))
109 (defalias 'gnome-c-snippet--format-Class 'gnome-c-snippet--format-Package)
110
111 (defun gnome-c-snippet--format-PackageClass (package class)
112 (concat (gnome-c-snippet--format-Package package)
113 (gnome-c-snippet--format-Class class)))
114
115 ;;;###autoload
116 (defun gnome-c-snippet-insert-package_class (package class)
117 "Insert the class name before the current point."
118 (interactive (gnome-c-snippet--read-package-and-class
119 nil nil
120 'gnome-c-snippet-package
121 'gnome-c-snippet-class))
122 (insert (gnome-c-snippet--format-package_class package class)))
123
124 ;;;###autoload
125 (defun gnome-c-snippet-insert-PACKAGE_CLASS (package class)
126 "Insert the class name before the current point."
127 (interactive (gnome-c-snippet--read-package-and-class
128 nil nil
129 'gnome-c-snippet-package
130 'gnome-c-snippet-class))
131 (insert (gnome-c-snippet--format-PACKAGE_CLASS package class)))
132
133 ;;;###autoload
134 (defun gnome-c-snippet-insert-PackageClass (package class)
135 "Insert the class name (in CamelCase) before the current point."
136 (interactive (gnome-c-snippet--read-package-and-class
137 nil nil
138 'gnome-c-snippet-package
139 'gnome-c-snippet-class))
140 (insert (gnome-c-snippet--format-PackageClass package class)))
141
142 (defun gnome-c-snippet-insert-interface-declaration (package iface
143 parent-package parent-class)
144 "Insert interface declaration for PACKAGE and IFACE"
145 (interactive
146 (append (gnome-c-snippet--read-package-and-class
147 nil
148 "Interface (CamelCase): "
149 'gnome-c-snippet-package
150 'gnome-c-snippet-class)
151 (gnome-c-snippet--read-package-and-class
152 "Parent package (CamelCase): "
153 "Parent class (CamelCase): "
154 'gnome-c-snippet-parent-package
155 'gnome-c-snippet-parent-class)))
156 (insert "\
157 #define " (gnome-c-snippet--format-PACKAGE package) "_TYPE_" (gnome-c-snippet--format-CLASS iface) " (" (gnome-c-snippet--format-package package) "_" (gnome-c-snippet--format-class iface) "_get_type ())
158 G_DECLARE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", "
159 (gnome-c-snippet--format-package_class package iface) ", " (gnome-c-snippet--format-PACKAGE package) ", " (gnome-c-snippet--format-CLASS iface) ", " (gnome-c-snippet--format-PackageClass parent-package parent-class) ")
160 "))
161
162 (defun gnome-c-snippet--insert-class-declaration (package
163 class
164 parent-package
165 parent-class
166 derivable)
167 (insert "\
168 #define " (gnome-c-snippet--format-PACKAGE package) "_TYPE_" (gnome-c-snippet--format-CLASS class) " (" (gnome-c-snippet--format-package_class package class) "_get_type ())
169 G_DECLARE_" (if derivable "DERIVABLE" "FINAL") "_TYPE (" (gnome-c-snippet--format-PackageClass package class) ", "
170 (gnome-c-snippet--format-package_class package class) ", " (gnome-c-snippet--format-PACKAGE package) ", " (gnome-c-snippet--format-CLASS class) ", " (gnome-c-snippet--format-PackageClass parent-package parent-class) ")
171 "))
172
173 (defun gnome-c-snippet-insert-final-class-declaration (package
174 class
175 parent-package
176 parent-class)
177 "Insert final class declaration for PACKAGE and CLASS."
178 (interactive
179 (append (gnome-c-snippet--read-package-and-class
180 nil nil
181 'gnome-c-snippet-package
182 'gnome-c-snippet-class)
183 (gnome-c-snippet--read-package-and-class
184 "Parent package (CamelCase): "
185 "Parent class (CamelCase): "
186 'gnome-c-snippet-parent-package
187 'gnome-c-snippet-parent-class)))
188 (gnome-c-snippet--insert-class-declaration package
189 class
190 parent-package
191 parent-class
192 nil))
193
194 (defun gnome-c-snippet-insert-derivable-class-declaration (package
195 class
196 parent-package
197 parent-class)
198 "Insert derivable class declaration for PACKAGE and CLASS."
199 (interactive
200 (append (gnome-c-snippet--read-package-and-class
201 nil nil
202 'gnome-c-snippet-package
203 'gnome-c-snippet-class)
204 (gnome-c-snippet--read-package-and-class
205 "Parent package (CamelCase): "
206 "Parent class (CamelCase): "
207 'gnome-c-snippet-parent-package
208 'gnome-c-snippet-parent-class)))
209 (gnome-c-snippet--insert-class-declaration package
210 class
211 parent-package
212 parent-class
213 t))
214
215 (defun gnome-c-snippet-insert-interface-definition (package
216 iface
217 parent-package
218 parent-class)
219 "Insert class definition for PACKAGE and CLASS."
220 (interactive
221 (append (gnome-c-snippet--read-package-and-class
222 nil
223 "Interface (CamelCase): "
224 'gnome-c-snippet-package
225 'gnome-c-snippet-class)
226 (gnome-c-snippet--read-package-and-class
227 "Parent package (CamelCase): "
228 "Parent class (CamelCase): "
229 'gnome-c-snippet-parent-package
230 'gnome-c-snippet-parent-class)))
231 (insert "\
232 static void
233 " (gnome-c-snippet--format-package_class package iface) "_default_init (" (gnome-c-snippet--format-PackageClass package iface) "Interface *iface) {
234 }
235
236 G_DEFINE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", "
237 (gnome-c-snippet--format-package_class package iface) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ")
238 "))
239
240 (defun gnome-c-snippet--insert-class-definition (package
241 class
242 parent-package
243 parent-class
244 abstract)
245 (insert "\
246 G_DEFINE_" (if abstract "ABSTRACT_" "") "TYPE (" (gnome-c-snippet--format-PackageClass package class) ", "
247 (gnome-c-snippet--format-package_class package class) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ")
248
249 static void
250 " (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass)
251 {
252 }
253
254 static void
255 " (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self)
256 {
257 }
258 "))
259
260 (defun gnome-c-snippet-insert-class-definition (package
261 class
262 parent-package
263 parent-class)
264 "Insert class definition for PACKAGE and CLASS."
265 (interactive
266 (append (gnome-c-snippet--read-package-and-class
267 nil nil
268 'gnome-c-snippet-package
269 'gnome-c-snippet-class)
270 (gnome-c-snippet--read-package-and-class
271 "Parent package (CamelCase): "
272 "Parent class (CamelCase): "
273 'gnome-c-snippet-parent-package
274 'gnome-c-snippet-parent-class)))
275 (gnome-c-snippet--insert-class-definition package
276 class
277 parent-package
278 parent-class
279 nil))
280
281 (defun gnome-c-snippet-insert-abstract-class-definition (package
282 class
283 parent-package
284 parent-class)
285 "Insert abstract class definition for PACKAGE and CLASS."
286 (interactive
287 (append (gnome-c-snippet--read-package-and-class
288 nil nil
289 'gnome-c-snippet-package
290 'gnome-c-snippet-class)
291 (gnome-c-snippet--read-package-and-class
292 "Parent package (CamelCase): "
293 "Parent class (CamelCase): "
294 'gnome-c-snippet-parent-package
295 'gnome-c-snippet-parent-class)))
296 (gnome-c-snippet--insert-class-definition package
297 class
298 parent-package
299 parent-class
300 t))
301
302 (defun gnome-c-snippet-insert-constructor (package class)
303 "Insert 'constructor' vfunc of GObjectClass for PACKAGE and CLASS."
304 (interactive
305 (gnome-c-snippet--read-package-and-class
306 nil nil
307 'gnome-c-snippet-package
308 'gnome-c-snippet-class))
309 (let (arglist-start body-start)
310 (insert "\
311 static GObject *
312 " (gnome-c-snippet--format-package_class package class) "_constructor (")
313 (setq arglist-start (point-marker))
314 (insert "GType *object,
315 guint n_construct_properties,
316 GObjectConstructParam *construct_properties)\n")
317 (setq body-start (point-marker))
318 (if gnome-c-snippet-align-arglist
319 (progn
320 (goto-char arglist-start)
321 (gnome-c-align-arglist-at-point))
322 (indent-region arglist-start (point)))
323 (goto-char body-start)
324 (insert "{
325 " (gnome-c-snippet--format-PackageClass package class) " *self = "
326 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
327
328 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (type, n_construct_properties, construct_properties);
329 }
330 ")
331 (indent-region body-start (point))))
332
333 (defun gnome-c-snippet-insert-set_property (package class)
334 "Insert 'set_property' vfunc of GObjectClass for PACKAGE and CLASS."
335 (interactive
336 (gnome-c-snippet--read-package-and-class
337 nil nil
338 'gnome-c-snippet-package
339 'gnome-c-snippet-class))
340 (let (arglist-start body-start)
341 (insert "\
342 static void
343 " (gnome-c-snippet--format-package_class package class) "_set_property (")
344 (setq arglist-start (point-marker))
345 (insert "GObject *object,
346 guint prop_id,
347 const GValue *value,
348 GParamSpec *pspec)\n")
349 (setq body-start (point-marker))
350 (if gnome-c-snippet-align-arglist
351 (progn
352 (goto-char arglist-start)
353 (gnome-c-align-arglist-at-point))
354 (indent-region arglist-start (point)))
355 (goto-char body-start)
356 (insert "{
357 " (gnome-c-snippet--format-PackageClass package class) " *self = "
358 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
359
360 switch (prop_id)
361 {
362 default:
363 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
364 break;
365 }
366 }
367 ")
368 (indent-region body-start (point))))
369
370 (defun gnome-c-snippet-insert-get_property (package class)
371 "Insert 'get_property' vfunc of GObjectClass for PACKAGE and CLASS."
372 (interactive
373 (gnome-c-snippet--read-package-and-class
374 nil nil
375 'gnome-c-snippet-package
376 'gnome-c-snippet-class))
377 (let (arglist-start body-start)
378 (insert "\
379 static void
380 " (gnome-c-snippet--format-package_class package class) "_get_property (")
381 (setq arglist-start (point-marker))
382 (insert "GObject *object,
383 guint prop_id,
384 GValue *value,
385 GParamSpec *pspec)\n")
386 (setq body-start (point-marker))
387 (if gnome-c-snippet-align-arglist
388 (progn
389 (goto-char arglist-start)
390 (gnome-c-align-arglist-at-point))
391 (indent-region arglist-start (point)))
392 (goto-char body-start)
393 (insert "{
394 " (gnome-c-snippet--format-PackageClass package class) " *self = "
395 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
396
397 switch (prop_id)
398 {
399 default:
400 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
401 break;
402 }
403 }
404 ")
405 (indent-region body-start (point))))
406
407 (defun gnome-c-snippet-insert-dispose (package class)
408 "Insert 'dispose' vfunc of GObjectClass for PACKAGE and CLASS."
409 (interactive
410 (gnome-c-snippet--read-package-and-class
411 nil nil
412 'gnome-c-snippet-package
413 'gnome-c-snippet-class))
414 (let (body-start)
415 (insert "\
416 static void
417 " (gnome-c-snippet--format-package_class package class) "_dispose (GObject *object)\n")
418 (setq body-start (point-marker))
419 (insert "{
420 " (gnome-c-snippet--format-PackageClass package class) " *self = "
421 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
422
423 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispose (object);
424 }
425 ")
426 (indent-region body-start (point))))
427
428 (defun gnome-c-snippet-insert-finalize (package class)
429 "Insert 'finalize' vfunc of GObjectClass for PACKAGE and CLASS."
430 (interactive
431 (gnome-c-snippet--read-package-and-class
432 nil nil
433 'gnome-c-snippet-package
434 'gnome-c-snippet-class))
435 (let (body-start)
436 (insert "\
437 static void
438 " (gnome-c-snippet--format-package_class package class) "_finalize (GObject *object)\n")
439 (setq body-start (point-marker))
440 (insert "{
441 " (gnome-c-snippet--format-PackageClass package class) " *self = "
442 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
443
444 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->finalize (object);
445 }
446 ")
447 (indent-region body-start (point))))
448
449 (defun gnome-c-snippet-insert-dispatch_properties_changed (package class)
450 "Insert 'dispatch_properties_changed vfunc of GObjectClass for
451 PACKAGE and CLASS."
452 (interactive
453 (gnome-c-snippet--read-package-and-class
454 nil nil
455 'gnome-c-snippet-package
456 'gnome-c-snippet-class))
457 (let (arglist-start body-start)
458 (insert "\
459 static void
460 " (gnome-c-snippet--format-package_class package class) "_dispatch_properties_changed (")
461 (setq arglist-start (point-marker))
462 (insert "GObject *object,
463 guint n_pspecs,
464 GParamSpec **pspecs)\n")
465 (setq body-start (point-marker))
466 (if gnome-c-snippet-align-arglist
467 (progn
468 (goto-char arglist-start)
469 (gnome-c-align-arglist-at-point))
470 (indent-region arglist-start (point)))
471 (goto-char body-start)
472 (insert "{
473 " (gnome-c-snippet--format-PackageClass package class) " *self = "
474 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
475
476 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
477 }
478 ")
479 (indent-region body-start (point))))
480
481 (defun gnome-c-snippet-insert-notify (package class)
482 "Insert 'notify' vfunc of GObjectClass for PACKAGE and CLASS."
483 (interactive
484 (gnome-c-snippet--read-package-and-class
485 nil nil
486 'gnome-c-snippet-package
487 'gnome-c-snippet-class))
488 (let (arglist-start body-start)
489 (insert "\
490 static void
491 " (gnome-c-snippet--format-package_class package class) "_notify (")
492 (setq arglist-start (point-marker))
493 (insert "GObject *object,
494 GParamSpec *pspec)\n")
495 (setq body-start (point-marker))
496 (if gnome-c-snippet-align-arglist
497 (progn
498 (goto-char arglist-start)
499 (gnome-c-align-arglist-at-point))
500 (indent-region arglist-start (point)))
501 (insert "{
502 " (gnome-c-snippet--format-PackageClass package class) " *self = "
503 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
504
505 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->notify (object, pspec);
506 }
507 ")
508 (indent-region body-start (point))))
509
510 (defun gnome-c-snippet-insert-constructed (package class)
511 "Insert 'constructed' vfunc of GObjectClass for PACKAGE and CLASS."
512 (interactive
513 (gnome-c-snippet--read-package-and-class
514 nil nil
515 'gnome-c-snippet-package
516 'gnome-c-snippet-class))
517 (let (body-start)
518 (insert "\
519 static void
520 " (gnome-c-snippet--format-package_class package class) "_constructed (GObject *object)\n")
521 (setq body-start (point-marker))
522 (insert "{
523 " (gnome-c-snippet--format-PackageClass package class) " *self = "
524 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
525
526 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (object);
527 }
528 ")
529 (indent-region body-start (point))))
530
531 (defvar gnome-c-snippet-snippet-commands
532 '(("G_DECLARE_INTERFACE" . gnome-c-snippet-insert-interface-declaration)
533 ("G_DECLARE_FINAL_TYPE" . gnome-c-snippet-insert-final-class-declaration)
534 ("G_DECLARE_DERIVABLE_TYPE" .
535 gnome-c-snippet-insert-derivable-class-declaration)
536 ("G_DEFINE_INTERFACE" . gnome-c-snippet-insert-interface-definition)
537 ("G_DEFINE_TYPE" . gnome-c-snippet-insert-class-definition)
538 ("G_DEFINE_ABSTRACT_TYPE" .
539 gnome-c-snippet-insert-abstract-class-definition)
540 ("GObjectClass.constructor" . gnome-c-snippet-insert-constructor)
541 ("GObjectClass.set_property" . gnome-c-snippet-insert-set_property)
542 ("GObjectClass.get_property" . gnome-c-snippet-insert-get_property)
543 ("GObjectClass.dispose" . gnome-c-snippet-insert-dispose)
544 ("GObjectClass.finalize" . gnome-c-snippet-insert-finalize)
545 ("GObjectClass.dispatch_properties_changed" .
546 gnome-c-snippet-insert-dispatch_properties_changed)
547 ("GObjectClass.notify" . gnome-c-snippet-insert-notify)
548 ("GObjectClass.contructed" . gnome-c-snippet-insert-constructed)))
549
550 ;;;###autoload
551 (defun gnome-c-snippet-insert (snippet)
552 (interactive
553 (list (completing-read "Snippet: " gnome-c-snippet-snippet-commands nil t)))
554 (let ((entry (assoc snippet gnome-c-snippet-snippet-commands)))
555 (unless entry
556 (error "Unknown snippet: %s" snippet))
557 (call-interactively (cdr entry))))
558
559 (provide 'gnome-c-snippet)
560
561 ;;; gnome-c-snippet.el ends here