1 ;;; gnome-c-snippet.el --- GNOME-style code generation -*- lexical-binding: t; -*-
2 ;; Copyright (C) 2016 Free Software Foundation, Inc.
4 ;; Author: Daiki Ueno <ueno@gnu.org>
5 ;; Keywords: GNOME, 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 ;; FIXME: The snippets defined here could be rewritten in yasnippet
29 (require 'gnome-c-align)
34 (declare-function subword-forward "subword.el" (&optional arg))
36 (defvar gnome-c-snippet-package nil)
37 (make-variable-buffer-local 'gnome-c-snippet-package)
39 (defvar gnome-c-snippet-class nil)
40 (make-variable-buffer-local 'gnome-c-snippet-class)
42 (defvar gnome-c-snippet-parent-package nil)
43 (make-variable-buffer-local 'gnome-c-snippet-parent-package)
45 (defvar gnome-c-snippet-parent-class nil)
46 (make-variable-buffer-local 'gnome-c-snippet-parent-class)
48 (defcustom gnome-c-snippet-align-arglist t
49 "Whether to align argument list of the inserted snippet"
51 :group 'gnome-c-style)
53 (make-variable-buffer-local 'gnome-c-snippet-align-arglist)
55 (defun gnome-c-snippet--parse-name (name)
60 (goto-char (point-min))
62 ;; Skip characters not recognized by subword-mode.
63 (if (looking-at "[^[:lower:][:upper:][:digit:]]+")
64 (goto-char (match-end 0)))
65 (push (buffer-substring (point) (progn (subword-forward 1)
70 (defun gnome-c-snippet--read-package-and-class (package-prompt
74 (when (or current-prefix-arg
75 (not (and (symbol-value package-symbol)
76 (symbol-value class-symbol))))
78 (gnome-c-snippet--parse-name
79 (read-string (or package-prompt
80 "Package (CamelCase): ")
81 (if (symbol-value package-symbol)
82 (gnome-c-snippet--format-Package
83 (symbol-value package-symbol))))))
85 (gnome-c-snippet--parse-name
86 (read-string (or class-prompt
87 "Class (CamelCase): ")
88 (if (symbol-value class-symbol)
89 (gnome-c-snippet--format-Class
90 (symbol-value class-symbol)))))))
91 (list (symbol-value package-symbol) (symbol-value class-symbol)))
93 (defun gnome-c-snippet--format-PACKAGE (package)
94 (mapconcat #'upcase package "_"))
95 (defalias 'gnome-c-snippet--format-CLASS 'gnome-c-snippet--format-PACKAGE)
97 (defun gnome-c-snippet--format-PACKAGE_CLASS (package class)
98 (concat (gnome-c-snippet--format-PACKAGE package)
100 (gnome-c-snippet--format-CLASS class)))
102 (defun gnome-c-snippet--format-package (package)
103 (mapconcat #'downcase package "_"))
104 (defalias 'gnome-c-snippet--format-class 'gnome-c-snippet--format-package)
106 (defun gnome-c-snippet--format-package_class (package class)
107 (concat (gnome-c-snippet--format-package package)
109 (gnome-c-snippet--format-class class)))
111 (defun gnome-c-snippet--format-Package (package)
112 (mapconcat #'identity package ""))
113 (defalias 'gnome-c-snippet--format-Class 'gnome-c-snippet--format-Package)
115 (defun gnome-c-snippet--format-PackageClass (package class)
116 (concat (gnome-c-snippet--format-Package package)
117 (gnome-c-snippet--format-Class class)))
120 (defun gnome-c-snippet-insert-package_class (package class)
121 "Insert the class name before the current point."
122 (interactive (gnome-c-snippet--read-package-and-class
124 'gnome-c-snippet-package
125 'gnome-c-snippet-class))
126 (insert (gnome-c-snippet--format-package_class package class)))
129 (defun gnome-c-snippet-insert-PACKAGE_CLASS (package class)
130 "Insert the class name before the current point."
131 (interactive (gnome-c-snippet--read-package-and-class
133 'gnome-c-snippet-package
134 'gnome-c-snippet-class))
135 (insert (gnome-c-snippet--format-PACKAGE_CLASS package class)))
138 (defun gnome-c-snippet-insert-PackageClass (package class)
139 "Insert the class name (in CamelCase) before the current point."
140 (interactive (gnome-c-snippet--read-package-and-class
142 'gnome-c-snippet-package
143 'gnome-c-snippet-class))
144 (insert (gnome-c-snippet--format-PackageClass package class)))
146 (defun gnome-c-snippet-insert-interface-declaration (package iface
147 parent-package parent-class)
148 "Insert interface declaration for PACKAGE and IFACE"
150 (append (gnome-c-snippet--read-package-and-class
152 "Interface (CamelCase): "
153 'gnome-c-snippet-package
154 'gnome-c-snippet-class)
155 (gnome-c-snippet--read-package-and-class
156 "Parent package (CamelCase): "
157 "Parent class (CamelCase): "
158 'gnome-c-snippet-parent-package
159 'gnome-c-snippet-parent-class)))
161 #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 ())
162 G_DECLARE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", "
163 (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) ")
166 (defun gnome-c-snippet--insert-class-declaration (package
172 #define " (gnome-c-snippet--format-PACKAGE package) "_TYPE_" (gnome-c-snippet--format-CLASS class) " (" (gnome-c-snippet--format-package_class package class) "_get_type ())
173 G_DECLARE_" (if derivable "DERIVABLE" "FINAL") "_TYPE (" (gnome-c-snippet--format-PackageClass package class) ", "
174 (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) ")
177 (defun gnome-c-snippet-insert-final-class-declaration (package
181 "Insert final class declaration for PACKAGE and CLASS."
183 (append (gnome-c-snippet--read-package-and-class
185 'gnome-c-snippet-package
186 'gnome-c-snippet-class)
187 (gnome-c-snippet--read-package-and-class
188 "Parent package (CamelCase): "
189 "Parent class (CamelCase): "
190 'gnome-c-snippet-parent-package
191 'gnome-c-snippet-parent-class)))
192 (gnome-c-snippet--insert-class-declaration package
198 (defun gnome-c-snippet-insert-derivable-class-declaration (package
202 "Insert derivable class declaration for PACKAGE and CLASS."
204 (append (gnome-c-snippet--read-package-and-class
206 'gnome-c-snippet-package
207 'gnome-c-snippet-class)
208 (gnome-c-snippet--read-package-and-class
209 "Parent package (CamelCase): "
210 "Parent class (CamelCase): "
211 'gnome-c-snippet-parent-package
212 'gnome-c-snippet-parent-class)))
213 (gnome-c-snippet--insert-class-declaration package
219 (defun gnome-c-snippet-insert-interface-definition (package
223 "Insert class definition for PACKAGE and CLASS."
225 (append (gnome-c-snippet--read-package-and-class
227 "Interface (CamelCase): "
228 'gnome-c-snippet-package
229 'gnome-c-snippet-class)
230 (gnome-c-snippet--read-package-and-class
231 "Parent package (CamelCase): "
232 "Parent class (CamelCase): "
233 'gnome-c-snippet-parent-package
234 'gnome-c-snippet-parent-class)))
237 " (gnome-c-snippet--format-package_class package iface) "_default_init (" (gnome-c-snippet--format-PackageClass package iface) "Interface *iface) {
240 G_DEFINE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", "
241 (gnome-c-snippet--format-package_class package iface) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ")
244 (defun gnome-c-snippet--insert-class-definition (package
250 G_DEFINE_" (if abstract "ABSTRACT_" "") "TYPE (" (gnome-c-snippet--format-PackageClass package class) ", "
251 (gnome-c-snippet--format-package_class package class) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ")
254 " (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass)
259 " (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self)
264 (defun gnome-c-snippet-insert-class-definition (package
268 "Insert class definition for PACKAGE and CLASS."
270 (append (gnome-c-snippet--read-package-and-class
272 'gnome-c-snippet-package
273 'gnome-c-snippet-class)
274 (gnome-c-snippet--read-package-and-class
275 "Parent package (CamelCase): "
276 "Parent class (CamelCase): "
277 'gnome-c-snippet-parent-package
278 'gnome-c-snippet-parent-class)))
279 (gnome-c-snippet--insert-class-definition package
285 (defun gnome-c-snippet-insert-abstract-class-definition (package
289 "Insert abstract class definition for PACKAGE and CLASS."
291 (append (gnome-c-snippet--read-package-and-class
293 'gnome-c-snippet-package
294 'gnome-c-snippet-class)
295 (gnome-c-snippet--read-package-and-class
296 "Parent package (CamelCase): "
297 "Parent class (CamelCase): "
298 'gnome-c-snippet-parent-package
299 'gnome-c-snippet-parent-class)))
300 (gnome-c-snippet--insert-class-definition package
306 (defun gnome-c-snippet-insert-constructor (package class)
307 "Insert 'constructor' vfunc of GObjectClass for PACKAGE and CLASS."
309 (gnome-c-snippet--read-package-and-class
311 'gnome-c-snippet-package
312 'gnome-c-snippet-class))
313 (let (arglist-start body-start)
316 " (gnome-c-snippet--format-package_class package class) "_constructor (")
317 (setq arglist-start (point-marker))
318 (insert "GType *object,
319 guint n_construct_properties,
320 GObjectConstructParam *construct_properties)\n")
321 (setq body-start (point-marker))
322 (if gnome-c-snippet-align-arglist
324 (goto-char arglist-start)
325 (gnome-c-align-arglist-at-point))
326 (indent-region arglist-start (point)))
327 (goto-char body-start)
329 " (gnome-c-snippet--format-PackageClass package class) " *self = "
330 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
332 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (type, n_construct_properties, construct_properties);
335 (indent-region body-start (point))))
337 (defun gnome-c-snippet-insert-set_property (package class)
338 "Insert 'set_property' vfunc of GObjectClass for PACKAGE and CLASS."
340 (gnome-c-snippet--read-package-and-class
342 'gnome-c-snippet-package
343 'gnome-c-snippet-class))
344 (let (arglist-start body-start)
347 " (gnome-c-snippet--format-package_class package class) "_set_property (")
348 (setq arglist-start (point-marker))
349 (insert "GObject *object,
352 GParamSpec *pspec)\n")
353 (setq body-start (point-marker))
354 (if gnome-c-snippet-align-arglist
356 (goto-char arglist-start)
357 (gnome-c-align-arglist-at-point))
358 (indent-region arglist-start (point)))
359 (goto-char body-start)
361 " (gnome-c-snippet--format-PackageClass package class) " *self = "
362 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
367 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372 (indent-region body-start (point))))
374 (defun gnome-c-snippet-insert-get_property (package class)
375 "Insert 'get_property' vfunc of GObjectClass for PACKAGE and CLASS."
377 (gnome-c-snippet--read-package-and-class
379 'gnome-c-snippet-package
380 'gnome-c-snippet-class))
381 (let (arglist-start body-start)
384 " (gnome-c-snippet--format-package_class package class) "_get_property (")
385 (setq arglist-start (point-marker))
386 (insert "GObject *object,
389 GParamSpec *pspec)\n")
390 (setq body-start (point-marker))
391 (if gnome-c-snippet-align-arglist
393 (goto-char arglist-start)
394 (gnome-c-align-arglist-at-point))
395 (indent-region arglist-start (point)))
396 (goto-char body-start)
398 " (gnome-c-snippet--format-PackageClass package class) " *self = "
399 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
404 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
409 (indent-region body-start (point))))
411 (defun gnome-c-snippet-insert-dispose (package class)
412 "Insert 'dispose' vfunc of GObjectClass for PACKAGE and CLASS."
414 (gnome-c-snippet--read-package-and-class
416 'gnome-c-snippet-package
417 'gnome-c-snippet-class))
421 " (gnome-c-snippet--format-package_class package class) "_dispose (GObject *object)\n")
422 (setq body-start (point-marker))
424 " (gnome-c-snippet--format-PackageClass package class) " *self = "
425 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
427 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispose (object);
430 (indent-region body-start (point))))
432 (defun gnome-c-snippet-insert-finalize (package class)
433 "Insert 'finalize' vfunc of GObjectClass for PACKAGE and CLASS."
435 (gnome-c-snippet--read-package-and-class
437 'gnome-c-snippet-package
438 'gnome-c-snippet-class))
442 " (gnome-c-snippet--format-package_class package class) "_finalize (GObject *object)\n")
443 (setq body-start (point-marker))
445 " (gnome-c-snippet--format-PackageClass package class) " *self = "
446 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
448 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->finalize (object);
451 (indent-region body-start (point))))
453 (defun gnome-c-snippet-insert-dispatch_properties_changed (package class)
454 "Insert 'dispatch_properties_changed vfunc of GObjectClass for
457 (gnome-c-snippet--read-package-and-class
459 'gnome-c-snippet-package
460 'gnome-c-snippet-class))
461 (let (arglist-start body-start)
464 " (gnome-c-snippet--format-package_class package class) "_dispatch_properties_changed (")
465 (setq arglist-start (point-marker))
466 (insert "GObject *object,
468 GParamSpec **pspecs)\n")
469 (setq body-start (point-marker))
470 (if gnome-c-snippet-align-arglist
472 (goto-char arglist-start)
473 (gnome-c-align-arglist-at-point))
474 (indent-region arglist-start (point)))
475 (goto-char body-start)
477 " (gnome-c-snippet--format-PackageClass package class) " *self = "
478 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
480 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
483 (indent-region body-start (point))))
485 (defun gnome-c-snippet-insert-notify (package class)
486 "Insert 'notify' vfunc of GObjectClass for PACKAGE and CLASS."
488 (gnome-c-snippet--read-package-and-class
490 'gnome-c-snippet-package
491 'gnome-c-snippet-class))
492 (let (arglist-start body-start)
495 " (gnome-c-snippet--format-package_class package class) "_notify (")
496 (setq arglist-start (point-marker))
497 (insert "GObject *object,
498 GParamSpec *pspec)\n")
499 (setq body-start (point-marker))
500 (if gnome-c-snippet-align-arglist
502 (goto-char arglist-start)
503 (gnome-c-align-arglist-at-point))
504 (indent-region arglist-start (point)))
506 " (gnome-c-snippet--format-PackageClass package class) " *self = "
507 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
509 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->notify (object, pspec);
512 (indent-region body-start (point))))
514 (defun gnome-c-snippet-insert-constructed (package class)
515 "Insert 'constructed' vfunc of GObjectClass for PACKAGE and CLASS."
517 (gnome-c-snippet--read-package-and-class
519 'gnome-c-snippet-package
520 'gnome-c-snippet-class))
524 " (gnome-c-snippet--format-package_class package class) "_constructed (GObject *object)\n")
525 (setq body-start (point-marker))
527 " (gnome-c-snippet--format-PackageClass package class) " *self = "
528 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
530 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (object);
533 (indent-region body-start (point))))
535 (defvar gnome-c-snippet-snippet-commands
536 '(("G_DECLARE_INTERFACE" . gnome-c-snippet-insert-interface-declaration)
537 ("G_DECLARE_FINAL_TYPE" . gnome-c-snippet-insert-final-class-declaration)
538 ("G_DECLARE_DERIVABLE_TYPE" .
539 gnome-c-snippet-insert-derivable-class-declaration)
540 ("G_DEFINE_INTERFACE" . gnome-c-snippet-insert-interface-definition)
541 ("G_DEFINE_TYPE" . gnome-c-snippet-insert-class-definition)
542 ("G_DEFINE_ABSTRACT_TYPE" .
543 gnome-c-snippet-insert-abstract-class-definition)
544 ("GObjectClass.constructor" . gnome-c-snippet-insert-constructor)
545 ("GObjectClass.set_property" . gnome-c-snippet-insert-set_property)
546 ("GObjectClass.get_property" . gnome-c-snippet-insert-get_property)
547 ("GObjectClass.dispose" . gnome-c-snippet-insert-dispose)
548 ("GObjectClass.finalize" . gnome-c-snippet-insert-finalize)
549 ("GObjectClass.dispatch_properties_changed" .
550 gnome-c-snippet-insert-dispatch_properties_changed)
551 ("GObjectClass.notify" . gnome-c-snippet-insert-notify)
552 ("GObjectClass.contructed" . gnome-c-snippet-insert-constructed)))
555 (defun gnome-c-snippet-insert (snippet)
557 (list (completing-read "Snippet: " gnome-c-snippet-snippet-commands nil t)))
558 (let ((entry (assoc snippet gnome-c-snippet-snippet-commands)))
560 (error "Unknown snippet: %s" snippet))
561 (call-interactively (cdr entry))))
563 (provide 'gnome-c-snippet)
565 ;;; gnome-c-snippet.el ends here