X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/445258b7156a22c83cc2a4d206ee907bb2b3db09..30b18d1d6f7deb3b0a1973c87e77490e9a50c818:/packages/gnome-c-style/gnome-c-snippet.el diff --git a/packages/gnome-c-style/gnome-c-snippet.el b/packages/gnome-c-style/gnome-c-snippet.el new file mode 100644 index 000000000..ed3633672 --- /dev/null +++ b/packages/gnome-c-style/gnome-c-snippet.el @@ -0,0 +1,565 @@ +;;; gnome-c-snippet.el --- GNOME-style code generation -*- lexical-binding: t; -*- +;; Copyright (C) 2016 Free Software Foundation, Inc. + +;; Author: Daiki Ueno +;; Keywords: GNOME, C, coding style + +;; This file is not part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see +;; . + +;;; Commentary: + +;; FIXME: The snippets defined here could be rewritten in yasnippet + +;;; Code: + +(require 'gnome-c-align) + +(eval-when-compile + (require 'subword)) + +(declare-function subword-forward "subword.el" (&optional arg)) + +(defvar gnome-c-snippet-package nil) +(make-variable-buffer-local 'gnome-c-snippet-package) + +(defvar gnome-c-snippet-class nil) +(make-variable-buffer-local 'gnome-c-snippet-class) + +(defvar gnome-c-snippet-parent-package nil) +(make-variable-buffer-local 'gnome-c-snippet-parent-package) + +(defvar gnome-c-snippet-parent-class nil) +(make-variable-buffer-local 'gnome-c-snippet-parent-class) + +(defcustom gnome-c-snippet-align-arglist t + "Whether to align argument list of the inserted snippet" + :type 'boolean + :group 'gnome-c-style) + +(make-variable-buffer-local 'gnome-c-snippet-align-arglist) + +(defun gnome-c-snippet--parse-name (name) + (require 'subword) + (with-temp-buffer + (let (words) + (insert name) + (goto-char (point-min)) + (while (not (eobp)) + ;; Skip characters not recognized by subword-mode. + (if (looking-at "[^[:lower:][:upper:][:digit:]]+") + (goto-char (match-end 0))) + (push (buffer-substring (point) (progn (subword-forward 1) + (point))) + words)) + (nreverse words)))) + +(defun gnome-c-snippet--read-package-and-class (package-prompt + class-prompt + package-symbol + class-symbol) + (when (or current-prefix-arg + (not (and (symbol-value package-symbol) + (symbol-value class-symbol)))) + (set package-symbol + (gnome-c-snippet--parse-name + (read-string (or package-prompt + "Package (CamelCase): ") + (if (symbol-value package-symbol) + (gnome-c-snippet--format-Package + (symbol-value package-symbol)))))) + (set class-symbol + (gnome-c-snippet--parse-name + (read-string (or class-prompt + "Class (CamelCase): ") + (if (symbol-value class-symbol) + (gnome-c-snippet--format-Class + (symbol-value class-symbol))))))) + (list (symbol-value package-symbol) (symbol-value class-symbol))) + +(defun gnome-c-snippet--format-PACKAGE (package) + (mapconcat #'upcase package "_")) +(defalias 'gnome-c-snippet--format-CLASS 'gnome-c-snippet--format-PACKAGE) + +(defun gnome-c-snippet--format-PACKAGE_CLASS (package class) + (concat (gnome-c-snippet--format-PACKAGE package) + "_" + (gnome-c-snippet--format-CLASS class))) + +(defun gnome-c-snippet--format-package (package) + (mapconcat #'downcase package "_")) +(defalias 'gnome-c-snippet--format-class 'gnome-c-snippet--format-package) + +(defun gnome-c-snippet--format-package_class (package class) + (concat (gnome-c-snippet--format-package package) + "_" + (gnome-c-snippet--format-class class))) + +(defun gnome-c-snippet--format-Package (package) + (mapconcat #'identity package "")) +(defalias 'gnome-c-snippet--format-Class 'gnome-c-snippet--format-Package) + +(defun gnome-c-snippet--format-PackageClass (package class) + (concat (gnome-c-snippet--format-Package package) + (gnome-c-snippet--format-Class class))) + +;;;###autoload +(defun gnome-c-snippet-insert-package_class (package class) + "Insert the class name before the current point." + (interactive (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (insert (gnome-c-snippet--format-package_class package class))) + +;;;###autoload +(defun gnome-c-snippet-insert-PACKAGE_CLASS (package class) + "Insert the class name before the current point." + (interactive (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (insert (gnome-c-snippet--format-PACKAGE_CLASS package class))) + +;;;###autoload +(defun gnome-c-snippet-insert-PackageClass (package class) + "Insert the class name (in CamelCase) before the current point." + (interactive (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (insert (gnome-c-snippet--format-PackageClass package class))) + +(defun gnome-c-snippet-insert-interface-declaration (package iface + parent-package parent-class) + "Insert interface declaration for PACKAGE and IFACE" + (interactive + (append (gnome-c-snippet--read-package-and-class + nil + "Interface (CamelCase): " + 'gnome-c-snippet-package + 'gnome-c-snippet-class) + (gnome-c-snippet--read-package-and-class + "Parent package (CamelCase): " + "Parent class (CamelCase): " + 'gnome-c-snippet-parent-package + 'gnome-c-snippet-parent-class))) + (insert "\ +#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 ()) +G_DECLARE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", " +(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) ") +")) + +(defun gnome-c-snippet--insert-class-declaration (package + class + parent-package + parent-class + derivable) + (insert "\ +#define " (gnome-c-snippet--format-PACKAGE package) "_TYPE_" (gnome-c-snippet--format-CLASS class) " (" (gnome-c-snippet--format-package_class package class) "_get_type ()) +G_DECLARE_" (if derivable "DERIVABLE" "FINAL") "_TYPE (" (gnome-c-snippet--format-PackageClass package class) ", " +(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) ") +")) + +(defun gnome-c-snippet-insert-final-class-declaration (package + class + parent-package + parent-class) + "Insert final class declaration for PACKAGE and CLASS." + (interactive + (append (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class) + (gnome-c-snippet--read-package-and-class + "Parent package (CamelCase): " + "Parent class (CamelCase): " + 'gnome-c-snippet-parent-package + 'gnome-c-snippet-parent-class))) + (gnome-c-snippet--insert-class-declaration package + class + parent-package + parent-class + nil)) + +(defun gnome-c-snippet-insert-derivable-class-declaration (package + class + parent-package + parent-class) + "Insert derivable class declaration for PACKAGE and CLASS." + (interactive + (append (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class) + (gnome-c-snippet--read-package-and-class + "Parent package (CamelCase): " + "Parent class (CamelCase): " + 'gnome-c-snippet-parent-package + 'gnome-c-snippet-parent-class))) + (gnome-c-snippet--insert-class-declaration package + class + parent-package + parent-class + t)) + +(defun gnome-c-snippet-insert-interface-definition (package + iface + parent-package + parent-class) + "Insert class definition for PACKAGE and CLASS." + (interactive + (append (gnome-c-snippet--read-package-and-class + nil + "Interface (CamelCase): " + 'gnome-c-snippet-package + 'gnome-c-snippet-class) + (gnome-c-snippet--read-package-and-class + "Parent package (CamelCase): " + "Parent class (CamelCase): " + 'gnome-c-snippet-parent-package + 'gnome-c-snippet-parent-class))) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package iface) "_default_init (" (gnome-c-snippet--format-PackageClass package iface) "Interface *iface) { +} + +G_DEFINE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", " +(gnome-c-snippet--format-package_class package iface) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ") +")) + +(defun gnome-c-snippet--insert-class-definition (package + class + parent-package + parent-class + abstract) + (insert "\ +G_DEFINE_" (if abstract "ABSTRACT_" "") "TYPE (" (gnome-c-snippet--format-PackageClass package class) ", " +(gnome-c-snippet--format-package_class package class) ", " (gnome-c-snippet--format-PACKAGE parent-package) "_TYPE_" (gnome-c-snippet--format-CLASS parent-class) ") + +static void +" (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass) +{ +} + +static void +" (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self) +{ +} +")) + +(defun gnome-c-snippet-insert-class-definition (package + class + parent-package + parent-class) + "Insert class definition for PACKAGE and CLASS." + (interactive + (append (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class) + (gnome-c-snippet--read-package-and-class + "Parent package (CamelCase): " + "Parent class (CamelCase): " + 'gnome-c-snippet-parent-package + 'gnome-c-snippet-parent-class))) + (gnome-c-snippet--insert-class-definition package + class + parent-package + parent-class + nil)) + +(defun gnome-c-snippet-insert-abstract-class-definition (package + class + parent-package + parent-class) + "Insert abstract class definition for PACKAGE and CLASS." + (interactive + (append (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class) + (gnome-c-snippet--read-package-and-class + "Parent package (CamelCase): " + "Parent class (CamelCase): " + 'gnome-c-snippet-parent-package + 'gnome-c-snippet-parent-class))) + (gnome-c-snippet--insert-class-definition package + class + parent-package + parent-class + t)) + +(defun gnome-c-snippet-insert-constructor (package class) + "Insert 'constructor' vfunc of GObjectClass for PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (arglist-start body-start) + (insert "\ +static GObject * +" (gnome-c-snippet--format-package_class package class) "_constructor (") + (setq arglist-start (point-marker)) + (insert "GType *object, +guint n_construct_properties, +GObjectConstructParam *construct_properties)\n") + (setq body-start (point-marker)) + (if gnome-c-snippet-align-arglist + (progn + (goto-char arglist-start) + (gnome-c-align-arglist-at-point)) + (indent-region arglist-start (point))) + (goto-char body-start) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (type, n_construct_properties, construct_properties); +} +") + (indent-region body-start (point)))) + +(defun gnome-c-snippet-insert-set_property (package class) + "Insert 'set_property' vfunc of GObjectClass for PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (arglist-start body-start) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package class) "_set_property (") + (setq arglist-start (point-marker)) + (insert "GObject *object, +guint prop_id, +const GValue *value, +GParamSpec *pspec)\n") + (setq body-start (point-marker)) + (if gnome-c-snippet-align-arglist + (progn + (goto-char arglist-start) + (gnome-c-align-arglist-at-point)) + (indent-region arglist-start (point))) + (goto-char body-start) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} +") + (indent-region body-start (point)))) + +(defun gnome-c-snippet-insert-get_property (package class) + "Insert 'get_property' vfunc of GObjectClass for PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (arglist-start body-start) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package class) "_get_property (") + (setq arglist-start (point-marker)) + (insert "GObject *object, +guint prop_id, +GValue *value, +GParamSpec *pspec)\n") + (setq body-start (point-marker)) + (if gnome-c-snippet-align-arglist + (progn + (goto-char arglist-start) + (gnome-c-align-arglist-at-point)) + (indent-region arglist-start (point))) + (goto-char body-start) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} +") + (indent-region body-start (point)))) + +(defun gnome-c-snippet-insert-dispose (package class) + "Insert 'dispose' vfunc of GObjectClass for PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (body-start) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package class) "_dispose (GObject *object)\n") + (setq body-start (point-marker)) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispose (object); +} +") + (indent-region body-start (point)))) + +(defun gnome-c-snippet-insert-finalize (package class) + "Insert 'finalize' vfunc of GObjectClass for PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (body-start) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package class) "_finalize (GObject *object)\n") + (setq body-start (point-marker)) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->finalize (object); +} +") + (indent-region body-start (point)))) + +(defun gnome-c-snippet-insert-dispatch_properties_changed (package class) + "Insert 'dispatch_properties_changed vfunc of GObjectClass for +PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (arglist-start body-start) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package class) "_dispatch_properties_changed (") + (setq arglist-start (point-marker)) + (insert "GObject *object, +guint n_pspecs, +GParamSpec **pspecs)\n") + (setq body-start (point-marker)) + (if gnome-c-snippet-align-arglist + (progn + (goto-char arglist-start) + (gnome-c-align-arglist-at-point)) + (indent-region arglist-start (point))) + (goto-char body-start) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs); +} +") + (indent-region body-start (point)))) + +(defun gnome-c-snippet-insert-notify (package class) + "Insert 'notify' vfunc of GObjectClass for PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (arglist-start body-start) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package class) "_notify (") + (setq arglist-start (point-marker)) + (insert "GObject *object, +GParamSpec *pspec)\n") + (setq body-start (point-marker)) + (if gnome-c-snippet-align-arglist + (progn + (goto-char arglist-start) + (gnome-c-align-arglist-at-point)) + (indent-region arglist-start (point))) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->notify (object, pspec); +} +") + (indent-region body-start (point)))) + +(defun gnome-c-snippet-insert-constructed (package class) + "Insert 'constructed' vfunc of GObjectClass for PACKAGE and CLASS." + (interactive + (gnome-c-snippet--read-package-and-class + nil nil + 'gnome-c-snippet-package + 'gnome-c-snippet-class)) + (let (body-start) + (insert "\ +static void +" (gnome-c-snippet--format-package_class package class) "_constructed (GObject *object)\n") + (setq body-start (point-marker)) + (insert "{ + " (gnome-c-snippet--format-PackageClass package class) " *self = " + (gnome-c-snippet--format-PACKAGE_CLASS package class) " (object); + + G_OBJECT_CLASS (" (gnome-c-snippet--format-package_class package class) "_parent_class)->constructed (object); +} +") + (indent-region body-start (point)))) + +(defvar gnome-c-snippet-snippet-commands + '(("G_DECLARE_INTERFACE" . gnome-c-snippet-insert-interface-declaration) + ("G_DECLARE_FINAL_TYPE" . gnome-c-snippet-insert-final-class-declaration) + ("G_DECLARE_DERIVABLE_TYPE" . + gnome-c-snippet-insert-derivable-class-declaration) + ("G_DEFINE_INTERFACE" . gnome-c-snippet-insert-interface-definition) + ("G_DEFINE_TYPE" . gnome-c-snippet-insert-class-definition) + ("G_DEFINE_ABSTRACT_TYPE" . + gnome-c-snippet-insert-abstract-class-definition) + ("GObjectClass.constructor" . gnome-c-snippet-insert-constructor) + ("GObjectClass.set_property" . gnome-c-snippet-insert-set_property) + ("GObjectClass.get_property" . gnome-c-snippet-insert-get_property) + ("GObjectClass.dispose" . gnome-c-snippet-insert-dispose) + ("GObjectClass.finalize" . gnome-c-snippet-insert-finalize) + ("GObjectClass.dispatch_properties_changed" . + gnome-c-snippet-insert-dispatch_properties_changed) + ("GObjectClass.notify" . gnome-c-snippet-insert-notify) + ("GObjectClass.contructed" . gnome-c-snippet-insert-constructed))) + +;;;###autoload +(defun gnome-c-snippet-insert (snippet) + (interactive + (list (completing-read "Snippet: " gnome-c-snippet-snippet-commands nil t))) + (let ((entry (assoc snippet gnome-c-snippet-snippet-commands))) + (unless entry + (error "Unknown snippet: %s" snippet)) + (call-interactively (cdr entry)))) + +(provide 'gnome-c-snippet) + +;;; gnome-c-snippet.el ends here