commit 50d88f1f4487a763112029a97dd92696640f2194 Author: Gergely Polonkai Date: Sat Oct 4 02:55:11 2014 +0200 Initial version It is already working, but undocumented. It is actually the widgetified version of Gustavo Sverzut Barbieri's gobject-class.el with some minor modifications. diff --git a/gobgen.el b/gobgen.el new file mode 100644 index 0000000..2c3e551 --- /dev/null +++ b/gobgen.el @@ -0,0 +1,340 @@ +;;; gobgen.el --- Generate GObject descendants using a detailed form +;; Author: Gergely Polonkai +;; Copyright: GPL +;; URL: https://github.com/gergelypolonkai/gobgen.el +;; Keywords: gobject, glib, gtk, helper, utilities +;;; Commentary: +;; Generator code is highly based on Gustavo Sverzut Barbieri's +;; gobject-class.el +;;; Code: + + +(require 'widget) + +(eval-when-compile (require 'wid-edit)) + +(defvar gobgen-widget-name) +(defvar gobgen-widget-prefix) +(defvar gobgen-widget-parent-name) +(defvar gobgen-widget-parent-prefix) +(defvar gobgen-widget-recent) +(defvar gobgen-widget-private) + +(defun string-has-prefix (full-str prefix-str) + "Check if full-str has the prefix prefix-str" + + (let* ((prefix-length (length prefix-str))) + (string-equal prefix-str (substring full-str 0 prefix-length)))) + +(defun get-gobject-prefix (class-name) + (car (split-string class-name "_"))) + +(defun gobgen-gen-header () + + (concat + "#ifndef __" + CLASS_FULL_NAME + "_H__\n" + + "#define __" + CLASS_FULL_NAME + "_H__\n" + + "\n" + + (if (string-equal "g" parent_prefix) + "#include " + (if (string-equal "gtk" parent_prefix) + "#include " + (concat "// You might want to revise this\n" + "#include <" + parent-header + ">"))) + "\n" + + "\n" + + "G_BEGIN_DECLS\n" + + "\n" + + "#define " CLASS_PREFIX "_TYPE_" CLASS_NAME " (" func-prefix "_get_type())\n" + + "#define " CLASS_FULL_NAME "(o) (G_TYPE_CHECK_INSTANCE_CAST((o), " CLASS_PREFIX "_TYPE_" CLASS_NAME ", " ClassFullName "))\n" + + "#define " CLASS_FULL_NAME "_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), " CLASS_PREFIX "_TYPE_" CLASS_NAME ", " ClassFullName "Class))\n" + + "#define " CLASS_PREFIX "_IS_" CLASS_NAME "(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), " CLASS_PREFIX "_TYPE_" CLASS_NAME "))\n" + + "#define " CLASS_PREFIX "_IS_" CLASS_NAME "_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), " CLASS_PREFIX "_TYPE_" CLASS_NAME "))\n" + + "#define " CLASS_FULL_NAME"_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), " CLASS_PREFIX "_TYPE_" CLASS_NAME ", " ClassFullName "Class))\n" + + "\n" + + "typedef struct _" ClassFullName " " ClassFullName ";\n" + + "typedef struct _" ClassFullName "Class " ClassFullName "Class;\n" + + (if (and (not recent-glib) need-private) + (concat "typedef struct _" ClassFullName "Private " ClassFullName "Private;\n")) + + "\n" + + "struct _" ClassFullName " {\n" + + " /* Parent instance structure */\n" + + " " ParentPrefix ParentName " parent_instance;\n" + + "\n" + + " /* Instance members */\n" + + (if (and (not recent-glib) need-private) + (concat "\n" + " /*< private >*/\n" + " " ClassFullName "Private *priv;\n")) + + "};\n" + + "\n" + + "struct _" ClassFullName "Class {\n" + + " " ParentPrefix ParentName "Class parent_class;\n" + + "};\n" + + "\n" + + "GType " func-prefix "_get_type(void) G_GNUC_CONST;\n" + + "\n" + + "G_END_DECLS\n" + + "\n" + + "#endif /* __" + CLASS_FULL_NAME + "_H__ */\n")) + +(defun gobgen-gen-code () + (concat + "#include \"" file-name-header "\"\n" + + "\n" + + (if need-private + (concat + (if (not recent-glib) + (concat + "#define " CLASS_FULL_NAME "_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE( \\\n" + " (o), \\\n" + " " CLASS_PREFIX "_TYPE_" CLASS_NAME ", \\\n" + " " ClassFullName "Private \\\n" + " ))\n" + "\n")) + + (if recent-glib "typedef ") + + "struct _" ClassFullName "Private {\n" + " /* TODO: You must add something here, or GLib will produce warnings! */\n" + "}" + + (if recent-glib + (concat " " ClassFullName "Private")) + + ";\n" + "\n")) + + "G_DEFINE_TYPE" + + (if (and recent-glib need-private) + "_WITH_PRIVATE") + + "(" ClassFullName ", " func-prefix ", " PARENT_PREFIX "_TYPE_" PARENT_NAME ");\n" + + "\n" + + "static void\n" + func-prefix "_finalize(GObject *gobject)\n" + "{\n" + " g_signal_handlers_destroy(gobject);\n" + " G_OBJECT_CLASS(" func-prefix "_parent_class)->finalize(gobject);\n" + "}\n" + + "\n" + + "static void\n" + func-prefix "_class_init(" ClassFullName "Class *klass)\n" + "{\n" + " GObjectClass *gobject_class = G_OBJECT_CLASS(klass);\n" + "\n" + + (if (and (not recent-glib) need-private) + (concat + " g_type_class_add_private(klass, sizeof(" ClassFullName "Private);\n" + "\n")) + + " gobject_class->finalize = " func-prefix "_finalize;\n" + + "}\n" + + "\n" + + "static void\n" + func-prefix "_init(" ClassFullName " *" class_name ")\n" + "{\n" + + (if (and (not recent-glib) need-private) + (concat + " " class_name "->priv = " CLASS_FULL_NAME "_GET_PRIVATE(" class_name ");\n")) + + "}\n")) + +(defun gobgen-generator () + "Generate the header definition for a GObject derived clas. + +Parameters: +" + (let* ((parent-prefix (downcase parent-prefix)) + (parent-name (downcase parent-name)) + (class-prefix (downcase class-prefix)) + (class-name (downcase class-name)) + (parent-prefix-length (length parent-prefix)) + (class-prefix-length (length class-prefix))) + + (if (not (string-has-prefix parent-name (concat parent-prefix "_"))) + (message (concat "Parent (" parent-name ") and parent prefix (" parent-prefix ") don't match")) + + (if (not (string-has-prefix class-name (concat class-prefix "_"))) + (message (concat "Class (" class-name ") and class prefix (" class-prefix ") don't match")) + + (let* ((parent-name (substring parent-name (+ parent-prefix-length 1))) + (class-name (substring class-name (+ class-prefix-length 1))) + (parent-prefix-pcs (split-string parent-prefix "_")) + (parent-name-pcs (split-string parent-name "_")) + (class-prefix-pcs (split-string class-prefix "_")) + (class-name-pcs (split-string class-name "_")) + (parent_prefix (string-join parent-prefix-pcs "_")) + (ParentPrefix (mapconcat 'capitalize parent-prefix-pcs "")) + (PARENT_PREFIX (upcase parent_prefix)) + (parent_name (string-join parent-name-pcs "_")) + (ParentName (mapconcat 'capitalize parent-name-pcs "")) + (PARENT_NAME (upcase parent_name)) + (class_prefix (string-join class-prefix-pcs "_")) + (ClassPrefix (mapconcat 'capitalize class-prefix-pcs "")) + (CLASS_PREFIX (upcase class_prefix)) + (class_name (string-join class-name-pcs "_")) + (ClassName (mapconcat 'capitalize class-name-pcs "")) + (CLASS_NAME (upcase class_name)) + (func-prefix (concat class_prefix "_" class_name)) + (ClassFullName (concat ClassPrefix ClassName)) + (CLASS_FULL_NAME (concat CLASS_PREFIX "_" CLASS_NAME)) + (parent-header (concat (string-join (append parent-prefix-pcs parent-name-pcs) "-") ".h")) + (file-name-base (string-join (append class-prefix-pcs class-name-pcs) "-")) + (file-name-code (concat file-name-base ".c")) + (file-name-header (concat file-name-base ".h"))) + + (delete-other-windows) + (split-window-vertically) + (other-window 1) + (find-file file-name-header) + (insert (gobgen-gen-header)) + + (split-window-vertically) + (other-window 1) + (find-file file-name-code) + (insert (gobgen-gen-code))))))) + +(defun gobgen () + "Create widgets window for GObject creation" + (interactive) + (switch-to-buffer "*GObject Creator*") + + (kill-all-local-variables) + + (let ((inhibit-read-only t)) + (erase-buffer)) + + (remove-overlays) + + (widget-insert "GObject Creator\n\n") + + (setq gobgen-widget-name + (widget-create 'editable-field + :size 25 + :format "Name: %v" + :notify (lambda (widget &rest ignore) + (widget-value-set gobgen-widget-prefix (get-gobject-prefix (widget-value widget)))) + "g_example_object")) + + (widget-insert " ") + + (setq gobgen-widget-prefix + (widget-create 'editable-field + :size 10 + :format "Prefix: %v\n" + "g")) + + (setq gobgen-widget-parent-name + (widget-create 'editable-field + :size 25 + :format "Parent: %v" + "g_object")) + + (widget-insert " ") + + (setq gobgen-widget-parent-prefix + (widget-create 'editable-field + :size 10 + :format "Prefix: %v\n" + "g")) + + (widget-insert "\n") + + (setq gobgen-widget-recent + (widget-create 'checkbox + t)) + + (widget-insert " GLib >= 2.38\n") + + (setq gobgen-widget-private + (widget-create 'checkbox + nil)) + + (widget-insert " Has private members\n") + + (widget-insert "\n\n") + + (widget-create 'push-button + :notify (lambda (&rest ignore) + (let ((class-name (widget-value gobgen-widget-name)) + (class-prefix (widget-value gobgen-widget-prefix)) + (parent-name (widget-value gobgen-widget-parent-name)) + (parent-prefix (widget-value gobgen-widget-parent-prefix)) + (recent-glib (widget-value gobgen-widget-recent)) + (need-private (widget-value gobgen-widget-private))) + (gobgen-generator))) + "Generate") + + (widget-insert " ") + + (widget-create 'push-button + :notify (lambda (&rest ignore) + (gobgen-widgets)) + "Reset form") + + (widget-insert " ") + + (widget-create 'push-button + :notify (lambda (&rest ignore) + (kill-buffer "*GObject Creator*")) + "Close") + + (beginning-of-buffer) + + (use-local-map widget-keymap) + (widget-setup))