1 ;;; gobject-snippet.el --- GObject code generation -*- lexical-binding: t; -*-
2 ;; Copyright (C) 2016 Daiki Ueno <ueno@gnu.org>
4 ;; Author: Daiki Ueno <ueno@gnu.org>
5 ;; Keywords: GObject, C, coding style
7 ;; This file is not part of GNU Emacs.
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.
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.
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/>.
25 (require 'gobject-align)
30 (declare-function subword-forward "subword.el" (&optional arg))
32 (defvar gobject-snippet-package nil)
33 (make-variable-buffer-local 'gobject-snippet-package)
35 (defvar gobject-snippet-class nil)
36 (make-variable-buffer-local 'gobject-snippet-class)
38 (defvar gobject-snippet-parent-package nil)
39 (make-variable-buffer-local 'gobject-snippet-parent-package)
41 (defvar gobject-snippet-parent-class nil)
42 (make-variable-buffer-local 'gobject-snippet-parent-class)
44 (defvar gobject-snippet-align-arglist nil)
45 (make-variable-buffer-local 'gobject-snippet-align-arglist)
47 (defun gobject-snippet--parse-name (name)
52 (goto-char (point-min))
54 ;; Skip characters not recognized by subword-mode.
55 (if (looking-at "[^[:lower:][:upper:][:digit:]]+")
56 (goto-char (match-end 0)))
57 (push (buffer-substring (point) (progn (subword-forward 1)
62 (defun gobject-snippet--read-package-and-class (package-prompt
66 (when (or current-prefix-arg
67 (not (and (symbol-value package-symbol)
68 (symbol-value class-symbol))))
70 (gobject-snippet--parse-name
71 (read-string (or package-prompt
72 "Package (CamelCase): ")
73 (if (symbol-value package-symbol)
74 (gobject-snippet--format-Package
75 (symbol-value package-symbol))))))
77 (gobject-snippet--parse-name
78 (read-string (or class-prompt
79 "Class (CamelCase): ")
80 (if (symbol-value class-symbol)
81 (gobject-snippet--format-Class
82 (symbol-value class-symbol)))))))
83 (list (symbol-value package-symbol) (symbol-value class-symbol)))
85 (defun gobject-snippet--format-PACKAGE (package)
86 (mapconcat #'upcase package "_"))
87 (defalias 'gobject-snippet--format-CLASS 'gobject-snippet--format-PACKAGE)
89 (defun gobject-snippet--format-PACKAGE_CLASS (package class)
90 (concat (gobject-snippet--format-PACKAGE package)
92 (gobject-snippet--format-CLASS class)))
94 (defun gobject-snippet--format-package (package)
95 (mapconcat #'downcase package "_"))
96 (defalias 'gobject-snippet--format-class 'gobject-snippet--format-package)
98 (defun gobject-snippet--format-package_class (package class)
99 (concat (gobject-snippet--format-package package)
101 (gobject-snippet--format-class class)))
103 (defun gobject-snippet--format-Package (package)
104 (mapconcat #'identity package ""))
105 (defalias 'gobject-snippet--format-Class 'gobject-snippet--format-Package)
107 (defun gobject-snippet--format-PackageClass (package class)
108 (concat (gobject-snippet--format-Package package)
109 (gobject-snippet--format-Class class)))
112 (defun gobject-snippet-insert-package_class (package class)
113 "Insert the class name before the current point."
114 (interactive (gobject-snippet--read-package-and-class
116 'gobject-snippet-package
117 'gobject-snippet-class))
118 (insert (gobject-snippet--format-package_class package class)))
121 (defun gobject-snippet-insert-PACKAGE_CLASS (package class)
122 "Insert the class name before the current point."
123 (interactive (gobject-snippet--read-package-and-class
125 'gobject-snippet-package
126 'gobject-snippet-class))
127 (insert (gobject-snippet--format-PACKAGE_CLASS package class)))
130 (defun gobject-snippet-insert-PackageClass (package class)
131 "Insert the class name (in CamelCase) before the current point."
132 (interactive (gobject-snippet--read-package-and-class
134 'gobject-snippet-package
135 'gobject-snippet-class))
136 (insert (gobject-snippet--format-PackageClass package class)))
138 (defun gobject-snippet-insert-interface-declaration (package iface
139 parent-package parent-class)
140 "Insert interface declaration for PACKAGE and IFACE"
142 (append (gobject-snippet--read-package-and-class
144 "Interface (CamelCase): "
145 'gobject-snippet-package
146 'gobject-snippet-class)
147 (gobject-snippet--read-package-and-class
148 "Parent package (CamelCase): "
149 "Parent class (CamelCase): "
150 'gobject-snippet-parent-package
151 'gobject-snippet-parent-class)))
153 #define " (gobject-snippet--format-PACKAGE package) "_TYPE_" (gobject-snippet--format-CLASS iface) " (" (gobject-snippet--format-package package) "_" (gobject-snippet--format-class iface) "_get_type ())
154 G_DECLARE_INTERFACE (" (gobject-snippet--format-PackageClass package iface) ", "
155 (gobject-snippet--format-package_class package iface) ", " (gobject-snippet--format-PACKAGE package) ", " (gobject-snippet--format-CLASS iface) ", " (gobject-snippet--format-PackageClass parent-package parent-class) ")
158 (defun gobject-snippet--insert-class-declaration (package
164 #define " (gobject-snippet--format-PACKAGE package) "_TYPE_" (gobject-snippet--format-CLASS class) " (" (gobject-snippet--format-package_class package class) "_get_type ())
165 G_DECLARE_" (if derivable "DERIVABLE" "FINAL") "_TYPE (" (gobject-snippet--format-PackageClass package class) ", "
166 (gobject-snippet--format-package_class package class) ", " (gobject-snippet--format-PACKAGE package) ", " (gobject-snippet--format-CLASS class) ", " (gobject-snippet--format-PackageClass parent-package parent-class) ")
169 (defun gobject-snippet-insert-final-class-declaration (package
173 "Insert final class declaration for PACKAGE and CLASS."
175 (append (gobject-snippet--read-package-and-class
177 'gobject-snippet-package
178 'gobject-snippet-class)
179 (gobject-snippet--read-package-and-class
180 "Parent package (CamelCase): "
181 "Parent class (CamelCase): "
182 'gobject-snippet-parent-package
183 'gobject-snippet-parent-class)))
184 (gobject-snippet--insert-class-declaration package
190 (defun gobject-snippet-insert-derivable-class-declaration (package
194 "Insert derivable class declaration for PACKAGE and CLASS."
196 (append (gobject-snippet--read-package-and-class
198 'gobject-snippet-package
199 'gobject-snippet-class)
200 (gobject-snippet--read-package-and-class
201 "Parent package (CamelCase): "
202 "Parent class (CamelCase): "
203 'gobject-snippet-parent-package
204 'gobject-snippet-parent-class)))
205 (gobject-snippet--insert-class-declaration package
211 (defun gobject-snippet-insert-interface-definition (package
215 "Insert class definition for PACKAGE and CLASS."
217 (append (gobject-snippet--read-package-and-class
219 "Interface (CamelCase): "
220 'gobject-snippet-package
221 'gobject-snippet-class)
222 (gobject-snippet--read-package-and-class
223 "Parent package (CamelCase): "
224 "Parent class (CamelCase): "
225 'gobject-snippet-parent-package
226 'gobject-snippet-parent-class)))
229 " (gobject-snippet--format-package_class package iface) "_default_init (" (gobject-snippet--format-PackageClass package iface) "Interface *iface) {
232 G_DEFINE_INTERFACE (" (gobject-snippet--format-PackageClass package iface) ", "
233 (gobject-snippet--format-package_class package iface) ", " (gobject-snippet--format-PACKAGE parent-package) "_TYPE_" (gobject-snippet--format-CLASS parent-class) ")
236 (defun gobject-snippet--insert-class-definition (package
242 G_DEFINE_" (if abstract "ABSTRACT_" "") "TYPE (" (gobject-snippet--format-PackageClass package class) ", "
243 (gobject-snippet--format-package_class package class) ", " (gobject-snippet--format-PACKAGE parent-package) "_TYPE_" (gobject-snippet--format-CLASS parent-class) ")
246 " (gobject-snippet--format-package_class package class) "_class_init (" (gobject-snippet--format-PackageClass package class) "Class *klass)
251 " (gobject-snippet--format-package_class package class) "_init (" (gobject-snippet--format-PackageClass package class) " *self)
256 (defun gobject-snippet-insert-class-definition (package
260 "Insert class definition for PACKAGE and CLASS."
262 (append (gobject-snippet--read-package-and-class
264 'gobject-snippet-package
265 'gobject-snippet-class)
266 (gobject-snippet--read-package-and-class
267 "Parent package (CamelCase): "
268 "Parent class (CamelCase): "
269 'gobject-snippet-parent-package
270 'gobject-snippet-parent-class)))
271 (gobject-snippet--insert-class-definition package
277 (defun gobject-snippet-insert-abstract-class-definition (package
281 "Insert abstract class definition for PACKAGE and CLASS."
283 (append (gobject-snippet--read-package-and-class
285 'gobject-snippet-package
286 'gobject-snippet-class)
287 (gobject-snippet--read-package-and-class
288 "Parent package (CamelCase): "
289 "Parent class (CamelCase): "
290 'gobject-snippet-parent-package
291 'gobject-snippet-parent-class)))
292 (gobject-snippet--insert-class-definition package
298 (defun gobject-snippet-insert-constructor (package class)
299 "Insert 'constructor' vfunc of GObjectClass for PACKAGE and CLASS."
301 (gobject-snippet--read-package-and-class
303 'gobject-snippet-package
304 'gobject-snippet-class))
305 (let (arglist-start body-start)
308 " (gobject-snippet--format-package_class package class) "_constructor (")
309 (setq arglist-start (point-marker))
310 (insert "GType *object,
311 guint n_construct_properties,
312 GObjectConstructParam *construct_properties")
313 (funcall (if gobject-snippet-align-arglist
314 #'gobject-align-region
316 arglist-start (point))
318 (setq body-start (point-marker))
320 " (gobject-snippet--format-PackageClass package class) " *self = "
321 (gobject-snippet--format-PACKAGE_CLASS package class) " (object);
323 G_OBJECT_CLASS (" (gobject-snippet--format-package_class package class) "_parent_class)->constructed (object);
326 (indent-region body-start (point))))
328 (defun gobject-snippet-insert-set_property (package class)
329 "Insert 'set_property' vfunc of GObjectClass for PACKAGE and CLASS."
331 (gobject-snippet--read-package-and-class
333 'gobject-snippet-package
334 'gobject-snippet-class))
335 (let (arglist-start body-start)
338 " (gobject-snippet--format-package_class package class) "_set_property (")
339 (setq arglist-start (point-marker))
340 (insert "GObject *object,
344 (funcall (if gobject-snippet-align-arglist
345 #'gobject-align-region
347 arglist-start (point))
349 (setq body-start (point-marker))
351 " (gobject-snippet--format-PackageClass package class) " *self = "
352 (gobject-snippet--format-PACKAGE_CLASS package class) " (object);
357 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362 (indent-region body-start (point))))
364 (defun gobject-snippet-insert-get_property (package class)
365 "Insert 'get_property' vfunc of GObjectClass for PACKAGE and CLASS."
367 (gobject-snippet--read-package-and-class
369 'gobject-snippet-package
370 'gobject-snippet-class))
371 (let (arglist-start body-start)
374 " (gobject-snippet--format-package_class package class) "_get_property (")
375 (setq arglist-start (point-marker))
376 (insert "GObject *object,
380 (funcall (if gobject-snippet-align-arglist
381 #'gobject-align-region
383 arglist-start (point))
385 (setq body-start (point-marker))
387 " (gobject-snippet--format-PackageClass package class) " *self = "
388 (gobject-snippet--format-PACKAGE_CLASS package class) " (object);
393 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
398 (indent-region body-start (point))))
400 (defun gobject-snippet-insert-dispose (package class)
401 "Insert 'dispose' vfunc of GObjectClass for PACKAGE and CLASS."
403 (gobject-snippet--read-package-and-class
405 'gobject-snippet-package
406 'gobject-snippet-class))
410 " (gobject-snippet--format-package_class package class) "_dispose (GObject *object)\n")
411 (setq body-start (point-marker))
413 " (gobject-snippet--format-PackageClass package class) " *self = "
414 (gobject-snippet--format-PACKAGE_CLASS package class) " (object);
416 G_OBJECT_CLASS (" (gobject-snippet--format-package_class package class) "_parent_class)->dispose (object);
419 (indent-region body-start (point))))
421 (defun gobject-snippet-insert-finalize (package class)
422 "Insert 'finalize' vfunc of GObjectClass for PACKAGE and CLASS."
424 (gobject-snippet--read-package-and-class
426 'gobject-snippet-package
427 'gobject-snippet-class))
431 " (gobject-snippet--format-package_class package class) "_finalize (GObject *object)\n")
432 (setq body-start (point-marker))
434 " (gobject-snippet--format-PackageClass package class) " *self = "
435 (gobject-snippet--format-PACKAGE_CLASS package class) " (object);
437 G_OBJECT_CLASS (" (gobject-snippet--format-package_class package class) "_parent_class)->finalize (object);
440 (indent-region body-start (point))))
442 (defun gobject-snippet-insert-notify (package class)
443 "Insert 'notify' vfunc of GObjectClass for PACKAGE and CLASS."
445 (gobject-snippet--read-package-and-class
447 'gobject-snippet-package
448 'gobject-snippet-class))
452 " (gobject-snippet--format-package_class package class) "_notify (GObject *object)\n")
453 (setq body-start (point-marker))
455 " (gobject-snippet--format-PackageClass package class) " *self = "
456 (gobject-snippet--format-PACKAGE_CLASS package class) " (object);
458 G_OBJECT_CLASS (" (gobject-snippet--format-package_class package class) "_parent_class)->finalize (object);
461 (indent-region body-start (point))))
463 (defun gobject-snippet-insert-constructed (package class)
464 "Insert 'constructed' vfunc of GObjectClass for PACKAGE and CLASS."
466 (gobject-snippet--read-package-and-class
468 'gobject-snippet-package
469 'gobject-snippet-class))
473 " (gobject-snippet--format-package_class package class) "_constructed (GObject *object)\n")
474 (setq body-start (point-marker))
476 " (gobject-snippet--format-PackageClass package class) " *self = "
477 (gobject-snippet--format-PACKAGE_CLASS package class) " (object);
479 G_OBJECT_CLASS (" (gobject-snippet--format-package_class package class) "_parent_class)->constructed (object);
482 (indent-region body-start (point))))
484 (defvar gobject-snippet-snippet-commands
485 '(("G_DECLARE_INTERFACE" . gobject-snippet-insert-interface-declaration)
486 ("G_DECLARE_FINAL_TYPE" . gobject-snippet-insert-final-class-declaration)
487 ("G_DECLARE_DERIVABLE_TYPE" .
488 gobject-snippet-insert-derivable-class-declaration)
489 ("G_DEFINE_INTERFACE" . gobject-snippet-insert-interface-definition)
490 ("G_DEFINE_TYPE" . gobject-snippet-insert-class-definition)
491 ("G_DEFINE_ABSTRACT_TYPE" .
492 gobject-snippet-insert-abstract-class-definition)
493 ("GObjectClass.constructor" . gobject-snippet-insert-constructor)
494 ("GObjectClass.set_property" . gobject-snippet-insert-set_property)
495 ("GObjectClass.get_property" . gobject-snippet-insert-get_property)
496 ("GObjectClass.dispose" . gobject-snippet-insert-dispose)
497 ("GObjectClass.finalize" . gobject-snippet-insert-finalize)
498 ;; GObjectClass.dispatch_properties_changed
499 ("GObjectClass.notify" . gobject-snippet-insert-notify)
500 ("GObjectClass.contructed" . gobject-snippet-insert-constructed)))
503 (defun gobject-snippet-insert (snippet)
505 (list (completing-read "Snippet: " gobject-snippet-snippet-commands nil t)))
506 (let ((entry (assoc snippet gobject-snippet-snippet-commands)))
508 (error "Unknown snippet: %s" snippet))
509 (call-interactively (cdr entry))))
511 (provide 'gobject-snippet)
513 ;;; gobject-snippet.el ends here