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