]> code.delx.au - gnu-emacs-elpa/blob - gnome-c-snippet.el
snippet: Refactor name prompt
[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-name (prompt symbol &optional default)
65 (when (or current-prefix-arg
66 (not (symbol-value symbol)))
67 (set symbol
68 (gnome-c-snippet--parse-name
69 (read-string prompt
70 (or (if (symbol-value symbol)
71 (gnome-c-snippet--format-Package
72 (symbol-value symbol)))
73 default)))))
74 (symbol-value symbol))
75
76 (defun gnome-c-snippet--read-package-and-class (parent)
77 (append (list (gnome-c-snippet--read-name
78 "Package (CamelCase): "
79 'gnome-c-snippet-package)
80 (gnome-c-snippet--read-name
81 "Class (CamelCase): "
82 'gnome-c-snippet-class))
83 (when parent
84 (list (gnome-c-snippet--read-name
85 "Parent package (CamelCase): "
86 'gnome-c-snippet-parent-package)
87 (gnome-c-snippet--read-name
88 "Parent class (CamelCase): "
89 'gnome-c-snippet-parent-class)))))
90
91 (defun gnome-c-snippet--read-package-and-interface (parent)
92 (list (gnome-c-snippet--read-name
93 "Package (CamelCase): "
94 'gnome-c-snippet-package)
95 (gnome-c-snippet--read-name
96 "Interface (CamelCase): "
97 'gnome-c-snippet-class)
98 (when parent
99 (list (gnome-c-snippet--read-name
100 "Parent package (CamelCase): "
101 'gnome-c-snippet-parent-package)
102 (gnome-c-snippet--read-name
103 "Parent class (CamelCase): "
104 'gnome-c-snippet-parent-class)))))
105
106 (defun gnome-c-snippet--format-PACKAGE (package)
107 (mapconcat #'upcase package "_"))
108 (defalias 'gnome-c-snippet--format-CLASS 'gnome-c-snippet--format-PACKAGE)
109
110 (defun gnome-c-snippet--format-PACKAGE_CLASS (package class)
111 (concat (gnome-c-snippet--format-PACKAGE package)
112 "_"
113 (gnome-c-snippet--format-CLASS class)))
114
115 (defun gnome-c-snippet--format-package (package)
116 (mapconcat #'downcase package "_"))
117 (defalias 'gnome-c-snippet--format-class 'gnome-c-snippet--format-package)
118
119 (defun gnome-c-snippet--format-package_class (package class)
120 (concat (gnome-c-snippet--format-package package)
121 "_"
122 (gnome-c-snippet--format-class class)))
123
124 (defun gnome-c-snippet--format-Package (package)
125 (mapconcat #'identity package ""))
126 (defalias 'gnome-c-snippet--format-Class 'gnome-c-snippet--format-Package)
127
128 (defun gnome-c-snippet--format-PackageClass (package class)
129 (concat (gnome-c-snippet--format-Package package)
130 (gnome-c-snippet--format-Class class)))
131
132 ;;;###autoload
133 (defun gnome-c-snippet-insert-package_class (package class)
134 "Insert the class name before the current point."
135 (interactive (gnome-c-snippet--read-package-and-class nil))
136 (insert (gnome-c-snippet--format-package_class package class)))
137
138 ;;;###autoload
139 (defun gnome-c-snippet-insert-PACKAGE_CLASS (package class)
140 "Insert the class name before the current point."
141 (interactive (gnome-c-snippet--read-package-and-class nil))
142 (insert (gnome-c-snippet--format-PACKAGE_CLASS package class)))
143
144 ;;;###autoload
145 (defun gnome-c-snippet-insert-PackageClass (package class)
146 "Insert the class name (in CamelCase) before the current point."
147 (interactive (gnome-c-snippet--read-package-and-class nil))
148 (insert (gnome-c-snippet--format-PackageClass package class)))
149
150 (defun gnome-c-snippet-insert-interface-declaration (package iface
151 parent-package parent-class)
152 "Insert interface declaration for PACKAGE and IFACE"
153 (interactive (gnome-c-snippet--read-package-and-interface t))
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 (gnome-c-snippet--read-package-and-class t))
177 (gnome-c-snippet--insert-class-declaration package
178 class
179 parent-package
180 parent-class
181 nil))
182
183 (defun gnome-c-snippet-insert-derivable-class-declaration (package
184 class
185 parent-package
186 parent-class)
187 "Insert derivable class declaration for PACKAGE and CLASS."
188 (interactive (gnome-c-snippet--read-package-and-class t))
189 (gnome-c-snippet--insert-class-declaration package
190 class
191 parent-package
192 parent-class
193 t))
194
195 (defun gnome-c-snippet-insert-interface-definition (package
196 iface
197 parent-package
198 parent-class)
199 "Insert class definition for PACKAGE and CLASS."
200 (interactive (gnome-c-snippet--read-package-and-interface t))
201 (insert "\
202 static void
203 " (gnome-c-snippet--format-package_class package iface) "_default_init (" (gnome-c-snippet--format-PackageClass package iface) "Interface *iface) {
204 }
205
206 G_DEFINE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", "
207 (gnome-c-snippet--format-package_class package iface) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ")
208 "))
209
210 (defun gnome-c-snippet--insert-class-definition (package
211 class
212 parent-package
213 parent-class
214 abstract)
215 (insert "\
216 G_DEFINE_" (if abstract "ABSTRACT_" "") "TYPE (" (gnome-c-snippet--format-PackageClass package class) ", "
217 (gnome-c-snippet--format-package_class package class) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ")
218
219 static void
220 " (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass)
221 {
222 }
223
224 static void
225 " (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self)
226 {
227 }
228 "))
229
230 (defun gnome-c-snippet-insert-class-definition (package
231 class
232 parent-package
233 parent-class)
234 "Insert class definition for PACKAGE and CLASS."
235 (interactive (gnome-c-snippet--read-package-and-class t))
236 (gnome-c-snippet--insert-class-definition package
237 class
238 parent-package
239 parent-class
240 nil))
241
242 (defun gnome-c-snippet-insert-abstract-class-definition (package
243 class
244 parent-package
245 parent-class)
246 "Insert abstract class definition for PACKAGE and CLASS."
247 (interactive (gnome-c-snippet--read-package-and-class t))
248 (gnome-c-snippet--insert-class-definition package
249 class
250 parent-package
251 parent-class
252 t))
253
254 (defun gnome-c-snippet-insert-constructor (package class)
255 "Insert 'constructor' vfunc of GObjectClass for PACKAGE and CLASS."
256 (interactive (gnome-c-snippet--read-package-and-class nil))
257 (let (arglist-start body-start)
258 (insert "\
259 static GObject *
260 " (gnome-c-snippet--format-package_class package class) "_constructor (")
261 (setq arglist-start (point-marker))
262 (insert "GType *object,
263 guint n_construct_properties,
264 GObjectConstructParam *construct_properties)\n")
265 (setq body-start (point-marker))
266 (if gnome-c-snippet-align-arglist
267 (progn
268 (goto-char arglist-start)
269 (gnome-c-align-arglist-at-point))
270 (indent-region arglist-start (point)))
271 (goto-char body-start)
272 (insert "{
273 " (gnome-c-snippet--format-PackageClass package class) " *self = "
274 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
275
276 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructor (type, n_construct_properties, construct_properties);
277 }
278 ")
279 (indent-region body-start (point))))
280
281 (defun gnome-c-snippet-insert-set_property (package class)
282 "Insert 'set_property' vfunc of GObjectClass for PACKAGE and CLASS."
283 (interactive (gnome-c-snippet--read-package-and-class nil))
284 (let (arglist-start body-start)
285 (insert "\
286 static void
287 " (gnome-c-snippet--format-package_class package class) "_set_property (")
288 (setq arglist-start (point-marker))
289 (insert "GObject *object,
290 guint prop_id,
291 const GValue *value,
292 GParamSpec *pspec)\n")
293 (setq body-start (point-marker))
294 (if gnome-c-snippet-align-arglist
295 (progn
296 (goto-char arglist-start)
297 (gnome-c-align-arglist-at-point))
298 (indent-region arglist-start (point)))
299 (goto-char body-start)
300 (insert "{
301 " (gnome-c-snippet--format-PackageClass package class) " *self = "
302 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
303
304 switch (prop_id)
305 {
306 default:
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308 break;
309 }
310 }
311 ")
312 (indent-region body-start (point))))
313
314 (defun gnome-c-snippet-insert-get_property (package class)
315 "Insert 'get_property' vfunc of GObjectClass for PACKAGE and CLASS."
316 (interactive (gnome-c-snippet--read-package-and-class nil))
317 (let (arglist-start body-start)
318 (insert "\
319 static void
320 " (gnome-c-snippet--format-package_class package class) "_get_property (")
321 (setq arglist-start (point-marker))
322 (insert "GObject *object,
323 guint prop_id,
324 GValue *value,
325 GParamSpec *pspec)\n")
326 (setq body-start (point-marker))
327 (if gnome-c-snippet-align-arglist
328 (progn
329 (goto-char arglist-start)
330 (gnome-c-align-arglist-at-point))
331 (indent-region arglist-start (point)))
332 (goto-char body-start)
333 (insert "{
334 " (gnome-c-snippet--format-PackageClass package class) " *self = "
335 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
336
337 switch (prop_id)
338 {
339 default:
340 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341 break;
342 }
343 }
344 ")
345 (indent-region body-start (point))))
346
347 (defun gnome-c-snippet-insert-dispose (package class)
348 "Insert 'dispose' vfunc of GObjectClass for PACKAGE and CLASS."
349 (interactive (gnome-c-snippet--read-package-and-class nil))
350 (let (body-start)
351 (insert "\
352 static void
353 " (gnome-c-snippet--format-package_class package class) "_dispose (GObject *object)\n")
354 (setq body-start (point-marker))
355 (insert "{
356 " (gnome-c-snippet--format-PackageClass package class) " *self = "
357 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
358
359 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispose (object);
360 }
361 ")
362 (indent-region body-start (point))))
363
364 (defun gnome-c-snippet-insert-finalize (package class)
365 "Insert 'finalize' vfunc of GObjectClass for PACKAGE and CLASS."
366 (interactive (gnome-c-snippet--read-package-and-class nil))
367 (let (body-start)
368 (insert "\
369 static void
370 " (gnome-c-snippet--format-package_class package class) "_finalize (GObject *object)\n")
371 (setq body-start (point-marker))
372 (insert "{
373 " (gnome-c-snippet--format-PackageClass package class) " *self = "
374 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
375
376 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->finalize (object);
377 }
378 ")
379 (indent-region body-start (point))))
380
381 (defun gnome-c-snippet-insert-dispatch_properties_changed (package class)
382 "Insert 'dispatch_properties_changed vfunc of GObjectClass for
383 PACKAGE and CLASS."
384 (interactive (gnome-c-snippet--read-package-and-class nil))
385 (let (arglist-start body-start)
386 (insert "\
387 static void
388 " (gnome-c-snippet--format-package_class package class) "_dispatch_properties_changed (")
389 (setq arglist-start (point-marker))
390 (insert "GObject *object,
391 guint n_pspecs,
392 GParamSpec **pspecs)\n")
393 (setq body-start (point-marker))
394 (if gnome-c-snippet-align-arglist
395 (progn
396 (goto-char arglist-start)
397 (gnome-c-align-arglist-at-point))
398 (indent-region arglist-start (point)))
399 (goto-char body-start)
400 (insert "{
401 " (gnome-c-snippet--format-PackageClass package class) " *self = "
402 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
403
404 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
405 }
406 ")
407 (indent-region body-start (point))))
408
409 (defun gnome-c-snippet-insert-notify (package class)
410 "Insert 'notify' vfunc of GObjectClass for PACKAGE and CLASS."
411 (interactive (gnome-c-snippet--read-package-and-class nil))
412 (let (arglist-start body-start)
413 (insert "\
414 static void
415 " (gnome-c-snippet--format-package_class package class) "_notify (")
416 (setq arglist-start (point-marker))
417 (insert "GObject *object,
418 GParamSpec *pspec)\n")
419 (setq body-start (point-marker))
420 (if gnome-c-snippet-align-arglist
421 (progn
422 (goto-char arglist-start)
423 (gnome-c-align-arglist-at-point))
424 (indent-region arglist-start (point)))
425 (insert "{
426 " (gnome-c-snippet--format-PackageClass package class) " *self = "
427 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
428
429 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->notify (object, pspec);
430 }
431 ")
432 (indent-region body-start (point))))
433
434 (defun gnome-c-snippet-insert-constructed (package class)
435 "Insert 'constructed' vfunc of GObjectClass for PACKAGE and CLASS."
436 (interactive (gnome-c-snippet--read-package-and-class nil))
437 (let (body-start)
438 (insert "\
439 static void
440 " (gnome-c-snippet--format-package_class package class) "_constructed (GObject *object)\n")
441 (setq body-start (point-marker))
442 (insert "{
443 " (gnome-c-snippet--format-PackageClass package class) " *self = "
444 (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object);
445
446 G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (object);
447 }
448 ")
449 (indent-region body-start (point))))
450
451 (defvar gnome-c-snippet-snippet-commands
452 '(("G_DECLARE_INTERFACE" . gnome-c-snippet-insert-interface-declaration)
453 ("G_DECLARE_FINAL_TYPE" . gnome-c-snippet-insert-final-class-declaration)
454 ("G_DECLARE_DERIVABLE_TYPE" .
455 gnome-c-snippet-insert-derivable-class-declaration)
456 ("G_DEFINE_INTERFACE" . gnome-c-snippet-insert-interface-definition)
457 ("G_DEFINE_TYPE" . gnome-c-snippet-insert-class-definition)
458 ("G_DEFINE_ABSTRACT_TYPE" .
459 gnome-c-snippet-insert-abstract-class-definition)
460 ("GObjectClass.constructor" . gnome-c-snippet-insert-constructor)
461 ("GObjectClass.set_property" . gnome-c-snippet-insert-set_property)
462 ("GObjectClass.get_property" . gnome-c-snippet-insert-get_property)
463 ("GObjectClass.dispose" . gnome-c-snippet-insert-dispose)
464 ("GObjectClass.finalize" . gnome-c-snippet-insert-finalize)
465 ("GObjectClass.dispatch_properties_changed" .
466 gnome-c-snippet-insert-dispatch_properties_changed)
467 ("GObjectClass.notify" . gnome-c-snippet-insert-notify)
468 ("GObjectClass.constructed" . gnome-c-snippet-insert-constructed)))
469
470 ;;;###autoload
471 (defun gnome-c-snippet-insert (snippet)
472 (interactive
473 (list (completing-read "Snippet: " gnome-c-snippet-snippet-commands nil t)))
474 (let ((entry (assoc snippet gnome-c-snippet-snippet-commands)))
475 (unless entry
476 (error "Unknown snippet: %s" snippet))
477 (call-interactively (cdr entry))))
478
479 (provide 'gnome-c-snippet)
480
481 ;;; gnome-c-snippet.el ends here