1 ;;; gnome-c-snippet.el --- GNOME-style code generation -*- lexical-binding: t; -*-
2 ;; Copyright (C) 2016 Daiki Ueno <ueno@gnu.org>
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 (require 'gnome-c-align)
30 (declare-function subword-forward "subword.el" (&optional arg))
32 (defvar gnome-c-snippet-package nil)
33 (make-variable-buffer-local 'gnome-c-snippet-package)
35 (defvar gnome-c-snippet-class nil)
36 (make-variable-buffer-local 'gnome-c-snippet-class)
38 (defvar gnome-c-snippet-parent-package nil)
39 (make-variable-buffer-local 'gnome-c-snippet-parent-package)
41 (defvar gnome-c-snippet-parent-class nil)
42 (make-variable-buffer-local 'gnome-c-snippet-parent-class)
44 (defcustom gnome-c-snippet-align-arglist t
45 "Whether to align argument list of the inserted snippet"
47 :group 'gnome-c-style)
49 (make-variable-buffer-local 'gnome-c-snippet-align-arglist)
51 (defun gnome-c-snippet--parse-name (name)
56 (goto-char (point-min))
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)
66 (defun gnome-c-snippet--read-package-and-class (package-prompt
70 (when (or current-prefix-arg
71 (not (and (symbol-value package-symbol)
72 (symbol-value class-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))))))
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)))
89 (defun gnome-c-snippet--format-PACKAGE (package)
90 (mapconcat #'upcase package "_"))
91 (defalias 'gnome-c-snippet--format-CLASS 'gnome-c-snippet--format-PACKAGE)
93 (defun gnome-c-snippet--format-PACKAGE_CLASS (package class)
94 (concat (gnome-c-snippet--format-PACKAGE package)
96 (gnome-c-snippet--format-CLASS class)))
98 (defun gnome-c-snippet--format-package (package)
99 (mapconcat #'downcase package "_"))
100 (defalias 'gnome-c-snippet--format-class 'gnome-c-snippet--format-package)
102 (defun gnome-c-snippet--format-package_class (package class)
103 (concat (gnome-c-snippet--format-package package)
105 (gnome-c-snippet--format-class class)))
107 (defun gnome-c-snippet--format-Package (package)
108 (mapconcat #'identity package ""))
109 (defalias 'gnome-c-snippet--format-Class 'gnome-c-snippet--format-Package)
111 (defun gnome-c-snippet--format-PackageClass (package class)
112 (concat (gnome-c-snippet--format-Package package)
113 (gnome-c-snippet--format-Class class)))
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
120 'gnome-c-snippet-package
121 'gnome-c-snippet-class))
122 (insert (gnome-c-snippet--format-package_class package class)))
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
129 'gnome-c-snippet-package
130 'gnome-c-snippet-class))
131 (insert (gnome-c-snippet--format-PACKAGE_CLASS package class)))
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
138 'gnome-c-snippet-package
139 'gnome-c-snippet-class))
140 (insert (gnome-c-snippet--format-PackageClass package class)))
142 (defun gnome-c-snippet-insert-interface-declaration (package iface
143 parent-package parent-class)
144 "Insert interface declaration for PACKAGE and IFACE"
146 (append (gnome-c-snippet--read-package-and-class
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)))
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) ")
162 (defun gnome-c-snippet--insert-class-declaration (package
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) ")
173 (defun gnome-c-snippet-insert-final-class-declaration (package
177 "Insert final class declaration for PACKAGE and CLASS."
179 (append (gnome-c-snippet--read-package-and-class
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
194 (defun gnome-c-snippet-insert-derivable-class-declaration (package
198 "Insert derivable class declaration for PACKAGE and CLASS."
200 (append (gnome-c-snippet--read-package-and-class
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
215 (defun gnome-c-snippet-insert-interface-definition (package
219 "Insert class definition for PACKAGE and CLASS."
221 (append (gnome-c-snippet--read-package-and-class
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)))
233 " (gnome-c-snippet--format-package_class package iface) "_default_init (" (gnome-c-snippet--format-PackageClass package iface) "Interface *iface) {
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) ")
240 (defun gnome-c-snippet--insert-class-definition (package
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) ")
250 " (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass)
255 " (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self)
260 (defun gnome-c-snippet-insert-class-definition (package
264 "Insert class definition for PACKAGE and CLASS."
266 (append (gnome-c-snippet--read-package-and-class
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
281 (defun gnome-c-snippet-insert-abstract-class-definition (package
285 "Insert abstract class definition for PACKAGE and CLASS."
287 (append (gnome-c-snippet--read-package-and-class
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
302 (defun gnome-c-snippet-insert-constructor (package class)
303 "Insert 'constructor' vfunc of GObjectClass for PACKAGE and CLASS."
305 (gnome-c-snippet--read-package-and-class
307 'gnome-c-snippet-package
308 'gnome-c-snippet-class))
309 (let (arglist-start body-start)
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
320 (goto-char arglist-start)
321 (gnome-c-align-arglist-at-point))
322 (indent-region arglist-start (point)))
323 (goto-char body-start)
325 " (gnome-c-snippet--format-PackageClass package class) " *self = "
326 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
328 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (object);
331 (indent-region body-start (point))))
333 (defun gnome-c-snippet-insert-set_property (package class)
334 "Insert 'set_property' vfunc of GObjectClass for PACKAGE and CLASS."
336 (gnome-c-snippet--read-package-and-class
338 'gnome-c-snippet-package
339 'gnome-c-snippet-class))
340 (let (arglist-start body-start)
343 " (gnome-c-snippet--format-package_class package class) "_set_property (")
344 (setq arglist-start (point-marker))
345 (insert "GObject *object,
348 GParamSpec *pspec)\n")
349 (setq body-start (point-marker))
350 (if gnome-c-snippet-align-arglist
352 (goto-char arglist-start)
353 (gnome-c-align-arglist-at-point))
354 (indent-region arglist-start (point)))
355 (goto-char body-start)
357 " (gnome-c-snippet--format-PackageClass package class) " *self = "
358 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
363 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
368 (indent-region body-start (point))))
370 (defun gnome-c-snippet-insert-get_property (package class)
371 "Insert 'get_property' vfunc of GObjectClass for PACKAGE and CLASS."
373 (gnome-c-snippet--read-package-and-class
375 'gnome-c-snippet-package
376 'gnome-c-snippet-class))
377 (let (arglist-start body-start)
380 " (gnome-c-snippet--format-package_class package class) "_get_property (")
381 (setq arglist-start (point-marker))
382 (insert "GObject *object,
385 GParamSpec *pspec)\n")
386 (setq body-start (point-marker))
387 (if gnome-c-snippet-align-arglist
389 (goto-char arglist-start)
390 (gnome-c-align-arglist-at-point))
391 (indent-region arglist-start (point)))
392 (goto-char body-start)
394 " (gnome-c-snippet--format-PackageClass package class) " *self = "
395 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
400 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
405 (indent-region body-start (point))))
407 (defun gnome-c-snippet-insert-dispose (package class)
408 "Insert 'dispose' vfunc of GObjectClass for PACKAGE and CLASS."
410 (gnome-c-snippet--read-package-and-class
412 'gnome-c-snippet-package
413 'gnome-c-snippet-class))
417 " (gnome-c-snippet--format-package_class package class) "_dispose (GObject *object)\n")
418 (setq body-start (point-marker))
420 " (gnome-c-snippet--format-PackageClass package class) " *self = "
421 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
423 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispose (object);
426 (indent-region body-start (point))))
428 (defun gnome-c-snippet-insert-finalize (package class)
429 "Insert 'finalize' vfunc of GObjectClass for PACKAGE and CLASS."
431 (gnome-c-snippet--read-package-and-class
433 'gnome-c-snippet-package
434 'gnome-c-snippet-class))
438 " (gnome-c-snippet--format-package_class package class) "_finalize (GObject *object)\n")
439 (setq body-start (point-marker))
441 " (gnome-c-snippet--format-PackageClass package class) " *self = "
442 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
444 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->finalize (object);
447 (indent-region body-start (point))))
449 (defun gnome-c-snippet-insert-notify (package class)
450 "Insert 'notify' vfunc of GObjectClass for PACKAGE and CLASS."
452 (gnome-c-snippet--read-package-and-class
454 'gnome-c-snippet-package
455 'gnome-c-snippet-class))
459 " (gnome-c-snippet--format-package_class package class) "_notify (GObject *object)\n")
460 (setq body-start (point-marker))
462 " (gnome-c-snippet--format-PackageClass package class) " *self = "
463 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
465 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->finalize (object);
468 (indent-region body-start (point))))
470 (defun gnome-c-snippet-insert-constructed (package class)
471 "Insert 'constructed' vfunc of GObjectClass for PACKAGE and CLASS."
473 (gnome-c-snippet--read-package-and-class
475 'gnome-c-snippet-package
476 'gnome-c-snippet-class))
480 " (gnome-c-snippet--format-package_class package class) "_constructed (GObject *object)\n")
481 (setq body-start (point-marker))
483 " (gnome-c-snippet--format-PackageClass package class) " *self = "
484 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
486 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (object);
489 (indent-region body-start (point))))
491 (defvar gnome-c-snippet-snippet-commands
492 '(("G_DECLARE_INTERFACE" . gnome-c-snippet-insert-interface-declaration)
493 ("G_DECLARE_FINAL_TYPE" . gnome-c-snippet-insert-final-class-declaration)
494 ("G_DECLARE_DERIVABLE_TYPE" .
495 gnome-c-snippet-insert-derivable-class-declaration)
496 ("G_DEFINE_INTERFACE" . gnome-c-snippet-insert-interface-definition)
497 ("G_DEFINE_TYPE" . gnome-c-snippet-insert-class-definition)
498 ("G_DEFINE_ABSTRACT_TYPE" .
499 gnome-c-snippet-insert-abstract-class-definition)
500 ("GObjectClass.constructor" . gnome-c-snippet-insert-constructor)
501 ("GObjectClass.set_property" . gnome-c-snippet-insert-set_property)
502 ("GObjectClass.get_property" . gnome-c-snippet-insert-get_property)
503 ("GObjectClass.dispose" . gnome-c-snippet-insert-dispose)
504 ("GObjectClass.finalize" . gnome-c-snippet-insert-finalize)
505 ;; GObjectClass.dispatch_properties_changed
506 ("GObjectClass.notify" . gnome-c-snippet-insert-notify)
507 ("GObjectClass.contructed" . gnome-c-snippet-insert-constructed)))
510 (defun gnome-c-snippet-insert (snippet)
512 (list (completing-read "Snippet: " gnome-c-snippet-snippet-commands nil t)))
513 (let ((entry (assoc snippet gnome-c-snippet-snippet-commands)))
515 (error "Unknown snippet: %s" snippet))
516 (call-interactively (cdr entry))))
518 (provide 'gnome-c-snippet)
520 ;;; gnome-c-snippet.el ends here