]> code.delx.au - gnu-emacs-elpa/blob - packages/gnome-c-style/gnome-c-snippet.el
multishell - Merge edge-case but significant fixes
[gnu-emacs-elpa] / packages / gnome-c-style / 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 ;;; Commentary:
24
25 ;; FIXME: The snippets defined here could be rewritten in yasnippet
26
27 ;;; Code:
28
29 (require 'gnome-c-align)
30
31 (eval-when-compile
32 (require 'subword))
33
34 (declare-function subword-forward "subword.el" (&optional arg))
35
36 (defvar gnome-c-snippet-package nil)
37 (make-variable-buffer-local 'gnome-c-snippet-package)
38
39 (defvar gnome-c-snippet-class nil)
40 (make-variable-buffer-local 'gnome-c-snippet-class)
41
42 (defvar gnome-c-snippet-parent-package nil)
43 (make-variable-buffer-local 'gnome-c-snippet-parent-package)
44
45 (defvar gnome-c-snippet-parent-class nil)
46 (make-variable-buffer-local 'gnome-c-snippet-parent-class)
47
48 (defcustom gnome-c-snippet-align-arglist t
49 "Whether to align argument list of the inserted snippet"
50 :type 'boolean
51 :group 'gnome-c-style)
52
53 (make-variable-buffer-local 'gnome-c-snippet-align-arglist)
54
55 (defun gnome-c-snippet--parse-name (name)
56 (require 'subword)
57 (with-temp-buffer
58 (let (words)
59 (insert name)
60 (goto-char (point-min))
61 (while (not (eobp))
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)
66 (point)))
67 words))
68 (nreverse words))))
69
70 (defun gnome-c-snippet--read-package-and-class (package-prompt
71 class-prompt
72 package-symbol
73 class-symbol)
74 (when (or current-prefix-arg
75 (not (and (symbol-value package-symbol)
76 (symbol-value class-symbol))))
77 (set package-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))))))
84 (set class-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)))
92
93 (defun gnome-c-snippet--format-PACKAGE (package)
94 (mapconcat #'upcase package "_"))
95 (defalias 'gnome-c-snippet--format-CLASS 'gnome-c-snippet--format-PACKAGE)
96
97 (defun gnome-c-snippet--format-PACKAGE_CLASS (package class)
98 (concat (gnome-c-snippet--format-PACKAGE package)
99 "_"
100 (gnome-c-snippet--format-CLASS class)))
101
102 (defun gnome-c-snippet--format-package (package)
103 (mapconcat #'downcase package "_"))
104 (defalias 'gnome-c-snippet--format-class 'gnome-c-snippet--format-package)
105
106 (defun gnome-c-snippet--format-package_class (package class)
107 (concat (gnome-c-snippet--format-package package)
108 "_"
109 (gnome-c-snippet--format-class class)))
110
111 (defun gnome-c-snippet--format-Package (package)
112 (mapconcat #'identity package ""))
113 (defalias 'gnome-c-snippet--format-Class 'gnome-c-snippet--format-Package)
114
115 (defun gnome-c-snippet--format-PackageClass (package class)
116 (concat (gnome-c-snippet--format-Package package)
117 (gnome-c-snippet--format-Class class)))
118
119 ;;;###autoload
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
123 nil nil
124 'gnome-c-snippet-package
125 'gnome-c-snippet-class))
126 (insert (gnome-c-snippet--format-package_class package class)))
127
128 ;;;###autoload
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
132 nil nil
133 'gnome-c-snippet-package
134 'gnome-c-snippet-class))
135 (insert (gnome-c-snippet--format-PACKAGE_CLASS package class)))
136
137 ;;;###autoload
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
141 nil nil
142 'gnome-c-snippet-package
143 'gnome-c-snippet-class))
144 (insert (gnome-c-snippet--format-PackageClass package class)))
145
146 (defun gnome-c-snippet-insert-interface-declaration (package iface
147 parent-package parent-class)
148 "Insert interface declaration for PACKAGE and IFACE"
149 (interactive
150 (append (gnome-c-snippet--read-package-and-class
151 nil
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)))
160 (insert "\
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) ")
164 "))
165
166 (defun gnome-c-snippet--insert-class-declaration (package
167 class
168 parent-package
169 parent-class
170 derivable)
171 (insert "\
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) ")
175 "))
176
177 (defun gnome-c-snippet-insert-final-class-declaration (package
178 class
179 parent-package
180 parent-class)
181 "Insert final class declaration for PACKAGE and CLASS."
182 (interactive
183 (append (gnome-c-snippet--read-package-and-class
184 nil nil
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
193 class
194 parent-package
195 parent-class
196 nil))
197
198 (defun gnome-c-snippet-insert-derivable-class-declaration (package
199 class
200 parent-package
201 parent-class)
202 "Insert derivable class declaration for PACKAGE and CLASS."
203 (interactive
204 (append (gnome-c-snippet--read-package-and-class
205 nil nil
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
214 class
215 parent-package
216 parent-class
217 t))
218
219 (defun gnome-c-snippet-insert-interface-definition (package
220 iface
221 parent-package
222 parent-class)
223 "Insert class definition for PACKAGE and CLASS."
224 (interactive
225 (append (gnome-c-snippet--read-package-and-class
226 nil
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)))
235 (insert "\
236 static void
237 " (gnome-c-snippet--format-package_class package iface) "_default_init (" (gnome-c-snippet--format-PackageClass package iface) "Interface *iface) {
238 }
239
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) ")
242 "))
243
244 (defun gnome-c-snippet--insert-class-definition (package
245 class
246 parent-package
247 parent-class
248 abstract)
249 (insert "\
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) ")
252
253 static void
254 " (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass)
255 {
256 }
257
258 static void
259 " (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self)
260 {
261 }
262 "))
263
264 (defun gnome-c-snippet-insert-class-definition (package
265 class
266 parent-package
267 parent-class)
268 "Insert class definition for PACKAGE and CLASS."
269 (interactive
270 (append (gnome-c-snippet--read-package-and-class
271 nil nil
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
280 class
281 parent-package
282 parent-class
283 nil))
284
285 (defun gnome-c-snippet-insert-abstract-class-definition (package
286 class
287 parent-package
288 parent-class)
289 "Insert abstract class definition for PACKAGE and CLASS."
290 (interactive
291 (append (gnome-c-snippet--read-package-and-class
292 nil nil
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
301 class
302 parent-package
303 parent-class
304 t))
305
306 (defun gnome-c-snippet-insert-constructor (package class)
307 "Insert 'constructor' vfunc of GObjectClass for PACKAGE and CLASS."
308 (interactive
309 (gnome-c-snippet--read-package-and-class
310 nil nil
311 'gnome-c-snippet-package
312 'gnome-c-snippet-class))
313 (let (arglist-start body-start)
314 (insert "\
315 static GObject *
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
323 (progn
324 (goto-char arglist-start)
325 (gnome-c-align-arglist-at-point))
326 (indent-region arglist-start (point)))
327 (goto-char body-start)
328 (insert "{
329 " (gnome-c-snippet--format-PackageClass package class) " *self = "
330 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
331
332 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (type, n_construct_properties, construct_properties);
333 }
334 ")
335 (indent-region body-start (point))))
336
337 (defun gnome-c-snippet-insert-set_property (package class)
338 "Insert 'set_property' vfunc of GObjectClass for PACKAGE and CLASS."
339 (interactive
340 (gnome-c-snippet--read-package-and-class
341 nil nil
342 'gnome-c-snippet-package
343 'gnome-c-snippet-class))
344 (let (arglist-start body-start)
345 (insert "\
346 static void
347 " (gnome-c-snippet--format-package_class package class) "_set_property (")
348 (setq arglist-start (point-marker))
349 (insert "GObject *object,
350 guint prop_id,
351 const GValue *value,
352 GParamSpec *pspec)\n")
353 (setq body-start (point-marker))
354 (if gnome-c-snippet-align-arglist
355 (progn
356 (goto-char arglist-start)
357 (gnome-c-align-arglist-at-point))
358 (indent-region arglist-start (point)))
359 (goto-char body-start)
360 (insert "{
361 " (gnome-c-snippet--format-PackageClass package class) " *self = "
362 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
363
364 switch (prop_id)
365 {
366 default:
367 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
368 break;
369 }
370 }
371 ")
372 (indent-region body-start (point))))
373
374 (defun gnome-c-snippet-insert-get_property (package class)
375 "Insert 'get_property' vfunc of GObjectClass for PACKAGE and CLASS."
376 (interactive
377 (gnome-c-snippet--read-package-and-class
378 nil nil
379 'gnome-c-snippet-package
380 'gnome-c-snippet-class))
381 (let (arglist-start body-start)
382 (insert "\
383 static void
384 " (gnome-c-snippet--format-package_class package class) "_get_property (")
385 (setq arglist-start (point-marker))
386 (insert "GObject *object,
387 guint prop_id,
388 GValue *value,
389 GParamSpec *pspec)\n")
390 (setq body-start (point-marker))
391 (if gnome-c-snippet-align-arglist
392 (progn
393 (goto-char arglist-start)
394 (gnome-c-align-arglist-at-point))
395 (indent-region arglist-start (point)))
396 (goto-char body-start)
397 (insert "{
398 " (gnome-c-snippet--format-PackageClass package class) " *self = "
399 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
400
401 switch (prop_id)
402 {
403 default:
404 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
405 break;
406 }
407 }
408 ")
409 (indent-region body-start (point))))
410
411 (defun gnome-c-snippet-insert-dispose (package class)
412 "Insert 'dispose' vfunc of GObjectClass for PACKAGE and CLASS."
413 (interactive
414 (gnome-c-snippet--read-package-and-class
415 nil nil
416 'gnome-c-snippet-package
417 'gnome-c-snippet-class))
418 (let (body-start)
419 (insert "\
420 static void
421 " (gnome-c-snippet--format-package_class package class) "_dispose (GObject *object)\n")
422 (setq body-start (point-marker))
423 (insert "{
424 " (gnome-c-snippet--format-PackageClass package class) " *self = "
425 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
426
427 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispose (object);
428 }
429 ")
430 (indent-region body-start (point))))
431
432 (defun gnome-c-snippet-insert-finalize (package class)
433 "Insert 'finalize' vfunc of GObjectClass for PACKAGE and CLASS."
434 (interactive
435 (gnome-c-snippet--read-package-and-class
436 nil nil
437 'gnome-c-snippet-package
438 'gnome-c-snippet-class))
439 (let (body-start)
440 (insert "\
441 static void
442 " (gnome-c-snippet--format-package_class package class) "_finalize (GObject *object)\n")
443 (setq body-start (point-marker))
444 (insert "{
445 " (gnome-c-snippet--format-PackageClass package class) " *self = "
446 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
447
448 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->finalize (object);
449 }
450 ")
451 (indent-region body-start (point))))
452
453 (defun gnome-c-snippet-insert-dispatch_properties_changed (package class)
454 "Insert 'dispatch_properties_changed vfunc of GObjectClass for
455 PACKAGE and CLASS."
456 (interactive
457 (gnome-c-snippet--read-package-and-class
458 nil nil
459 'gnome-c-snippet-package
460 'gnome-c-snippet-class))
461 (let (arglist-start body-start)
462 (insert "\
463 static void
464 " (gnome-c-snippet--format-package_class package class) "_dispatch_properties_changed (")
465 (setq arglist-start (point-marker))
466 (insert "GObject *object,
467 guint n_pspecs,
468 GParamSpec **pspecs)\n")
469 (setq body-start (point-marker))
470 (if gnome-c-snippet-align-arglist
471 (progn
472 (goto-char arglist-start)
473 (gnome-c-align-arglist-at-point))
474 (indent-region arglist-start (point)))
475 (goto-char body-start)
476 (insert "{
477 " (gnome-c-snippet--format-PackageClass package class) " *self = "
478 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
479
480 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
481 }
482 ")
483 (indent-region body-start (point))))
484
485 (defun gnome-c-snippet-insert-notify (package class)
486 "Insert 'notify' vfunc of GObjectClass for PACKAGE and CLASS."
487 (interactive
488 (gnome-c-snippet--read-package-and-class
489 nil nil
490 'gnome-c-snippet-package
491 'gnome-c-snippet-class))
492 (let (arglist-start body-start)
493 (insert "\
494 static void
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
501 (progn
502 (goto-char arglist-start)
503 (gnome-c-align-arglist-at-point))
504 (indent-region arglist-start (point)))
505 (insert "{
506 " (gnome-c-snippet--format-PackageClass package class) " *self = "
507 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
508
509 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->notify (object, pspec);
510 }
511 ")
512 (indent-region body-start (point))))
513
514 (defun gnome-c-snippet-insert-constructed (package class)
515 "Insert 'constructed' vfunc of GObjectClass for PACKAGE and CLASS."
516 (interactive
517 (gnome-c-snippet--read-package-and-class
518 nil nil
519 'gnome-c-snippet-package
520 'gnome-c-snippet-class))
521 (let (body-start)
522 (insert "\
523 static void
524 " (gnome-c-snippet--format-package_class package class) "_constructed (GObject *object)\n")
525 (setq body-start (point-marker))
526 (insert "{
527 " (gnome-c-snippet--format-PackageClass package class) " *self = "
528 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
529
530 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (object);
531 }
532 ")
533 (indent-region body-start (point))))
534
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)))
553
554 ;;;###autoload
555 (defun gnome-c-snippet-insert (snippet)
556 (interactive
557 (list (completing-read "Snippet: " gnome-c-snippet-snippet-commands nil t)))
558 (let ((entry (assoc snippet gnome-c-snippet-snippet-commands)))
559 (unless entry
560 (error "Unknown snippet: %s" snippet))
561 (call-interactively (cdr entry))))
562
563 (provide 'gnome-c-snippet)
564
565 ;;; gnome-c-snippet.el ends here