]> code.delx.au - gnu-emacs-elpa/blobdiff - gnome-c-snippet.el
snippet: Improve _init prompt
[gnu-emacs-elpa] / gnome-c-snippet.el
index 4ea4b0a831f8118cb6b4c5f0ab17e783a91a0c7c..95c5f6df31bf2fc6c865981fa7fc82126a12fd03 100644 (file)
 (defvar gnome-c-snippet-parent-class nil)
 (make-variable-buffer-local 'gnome-c-snippet-parent-class)
 
+(defconst gnome-c-snippet-guess-name-functions
+  '(gnome-c-snippet--guess-name-from-header-buffer
+    gnome-c-snippet--guess-name-from-declaration
+    gnome-c-snippet--guess-name-from-file-name))
+
 (defcustom gnome-c-snippet-align-arglist t
   "Whether to align argument list of the inserted snippet"
   :type 'boolean
 
 (make-variable-buffer-local 'gnome-c-snippet-align-arglist)
 
+(defun gnome-c-snippet--find-declaration ()
+  (save-excursion
+    (let (beg end)
+      (goto-char (point-min))
+      (when (re-search-forward
+            "^G_DECLARE_\\(?:FINAL\\|DERIVABLE\\)_TYPE\\s-*("
+            nil t)
+       (setq beg (match-beginning 0))
+       (goto-char (match-end 0))
+       (backward-char)
+       (condition-case nil
+           (progn
+             (c-forward-sexp)
+             (setq end (point)))
+         (error)))
+      (when (and beg end)
+       (list beg end)))))
+
+(defun gnome-c-snippet--extract-names-from-declaration (beg end)
+  (save-excursion
+    (narrow-to-region beg end)
+    (goto-char (point-min))
+    (search-forward "(")
+    (c-forward-syntactic-ws)
+    (let ((capitalized-package-class
+          (buffer-substring-no-properties (point)
+                                          (progn
+                                            (c-forward-token-2)
+                                            (c-backward-syntactic-ws)
+                                            (point))))
+         uppercased-package uppercased-class
+         capitalized-package capitalized-class capitalized-parent)
+      (c-forward-syntactic-ws)
+      (c-forward-token-2 3)
+      (setq uppercased-package (split-string
+                               (buffer-substring (point)
+                                                 (progn
+                                                   (c-forward-token-2)
+                                                   (c-backward-syntactic-ws)
+                                                   (point)))
+                               "_"))
+      (c-forward-syntactic-ws)
+      (c-forward-token-2)
+      (setq uppercased-class (split-string
+                             (buffer-substring (point)
+                                               (progn
+                                                 (c-forward-token-2)
+                                                 (c-backward-syntactic-ws)
+                                                 (point)))
+                             "_"))
+      (c-forward-syntactic-ws)
+      (c-forward-token-2)
+      (setq capitalized-parent (gnome-c-snippet--parse-name
+                               (buffer-substring (point)
+                                                 (progn
+                                                   (c-forward-token-2)
+                                                   (c-backward-syntactic-ws)
+                                                   (point)))))
+      (catch 'error
+       (let ((index 0))
+         (dolist (uppercased uppercased-package)
+           (let* ((length (length uppercased))
+                  (capitalized
+                   (substring capitalized-package-class
+                              index (+ index length))))
+             (unless (equal (upcase capitalized) uppercased)
+               (throw 'error nil))
+             (push capitalized capitalized-package)
+             (setq index (+ index length))))
+         (dolist (uppercased uppercased-class)
+           (let* ((length (length uppercased))
+                  (capitalized
+                   (substring capitalized-package-class
+                              index (+ index length))))
+             (unless (equal (upcase capitalized) uppercased)
+               (throw 'error nil))
+             (push capitalized capitalized-class)
+             (setq index (+ index length))))))
+      (list (nreverse capitalized-package)
+           (nreverse capitalized-class)
+           capitalized-parent))))
+
+(defun gnome-c-snippet--find-header-buffer ()
+  (pcase (file-name-extension buffer-file-name)
+    ("h"
+     (current-buffer))
+    ("c"
+     (let ((header-file-name
+           (concat (file-name-sans-extension buffer-file-name) ".h")))
+       (cl-find-if
+       (lambda (buffer)
+         (with-current-buffer buffer
+           (equal buffer-file-name header-file-name)))
+       (buffer-list))))))
+
+(defun gnome-c-snippet--guess-name-from-header-buffer (symbol)
+  (let ((header-buffer (gnome-c-snippet--find-header-buffer)))
+    (when header-buffer
+      (with-current-buffer header-buffer
+       (symbol-value (intern (format "gnome-c-snippet-%S" symbol)))))))
+
+(defun gnome-c-snippet--guess-name-from-declaration (symbol)
+  (when (memq symbol '(package class parent-package parent-class))
+    (let ((header-buffer (gnome-c-snippet--find-header-buffer)))
+      (when header-buffer
+       (with-current-buffer header-buffer
+         (let ((region (gnome-c-snippet--find-declaration))
+               names)
+           (when region
+             (setq names
+                   (apply #'gnome-c-snippet--extract-names-from-declaration
+                          region))
+             (when names
+               (pcase symbol
+                 (`package (car names))
+                 (`class (nth 1 names))
+                 (`parent-package (list (car (nth 2 names))))
+                 (`parent-class (cdr (nth 2 names))))))))))))
+
+(defun gnome-c-snippet--guess-name-from-file-name (symbol)
+  (when (memq symbol '(package class))
+    (let ((filename (file-name-sans-extension
+                    (file-name-nondirectory buffer-file-name))))
+      (when (string-match-p "-" filename)
+       (let ((names (split-string filename "-")))
+         (pcase symbol
+           (`package (list (upcase-initials (car names))))
+           (`class (mapcar #'upcase-initials (cdr names)))))))))
+
 (defun gnome-c-snippet--parse-name (name)
   (with-temp-buffer
     (let (words)
 (defun gnome-c-snippet--read-package-and-class (parent)
   (append (list (gnome-c-snippet--read-name
                 "Package (CamelCase): "
-                'gnome-c-snippet-package)
+                'gnome-c-snippet-package
+                (gnome-c-snippet--format-Package
+                 (run-hook-with-args-until-success
+                  'gnome-c-snippet-guess-name-functions
+                  'package)))
                (gnome-c-snippet--read-name
                 "Class (CamelCase): "
-                'gnome-c-snippet-class))
+                'gnome-c-snippet-class
+                (gnome-c-snippet--format-Class
+                 (run-hook-with-args-until-success
+                  'gnome-c-snippet-guess-name-functions
+                  'class))))
          (when parent
            (list (gnome-c-snippet--read-name
                   "Parent package (CamelCase): "
-                  'gnome-c-snippet-parent-package)
+                  'gnome-c-snippet-parent-package
+                  (gnome-c-snippet--format-Package
+                   (run-hook-with-args-until-success
+                    'gnome-c-snippet-guess-name-functions
+                    'parent-package)))
                  (gnome-c-snippet--read-name
                   "Parent class (CamelCase): "
-                  'gnome-c-snippet-parent-class)))))
+                  'gnome-c-snippet-parent-class
+                  (gnome-c-snippet--format-Class
+                   (run-hook-with-args-until-success
+                    'gnome-c-snippet-guess-name-functions
+                    'parent-class)))))))
 
 (defun gnome-c-snippet--read-package-and-interface (parent)
   (list (gnome-c-snippet--read-name
          "Package (CamelCase): "
-         'gnome-c-snippet-package)
+         'gnome-c-snippet-package
+         (gnome-c-snippet--format-Package
+          (run-hook-with-args-until-success
+           'gnome-c-snippet-guess-name-functions
+           'package)))
         (gnome-c-snippet--read-name
          "Interface (CamelCase): "
-         'gnome-c-snippet-class)
+         'gnome-c-snippet-class
+         (gnome-c-snippet--format-Class
+          (run-hook-with-args-until-success
+           'gnome-c-snippet-guess-name-functions
+           'class)))
         (when parent
           (list (gnome-c-snippet--read-name
                  "Parent package (CamelCase): "
-                 'gnome-c-snippet-parent-package)
+                 'gnome-c-snippet-parent-package
+                 (gnome-c-snippet--format-Package
+                  (run-hook-with-args-until-success
+                   'gnome-c-snippet-guess-name-functions
+                   'parent-package)))
                 (gnome-c-snippet--read-name
                  "Parent class (CamelCase): "
-                 'gnome-c-snippet-parent-class)))))
+                 'gnome-c-snippet-parent-class
+                  (gnome-c-snippet--format-Class
+                   (run-hook-with-args-until-success
+                    'gnome-c-snippet-guess-name-functions
+                    'parent-class)))))))
 
 (defun gnome-c-snippet--format-PACKAGE (package)
   (mapconcat #'upcase package "_"))
@@ -211,44 +377,62 @@ G_DEFINE_INTERFACE (" (gnome-c-snippet--format-PackageClass package iface) ", "
                                                 class
                                                 parent-package
                                                 parent-class
-                                                abstract)
+                                                abstract
+                                                code)
   (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) ")
+G_DEFINE_" (if abstract "ABSTRACT_" "") "TYPE" (if code "WITH_CODE" "") " (" (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) (if code ", " "") ")"))
 
-static void
-" (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass)
-{
-}
+(defun gnome-c-snippet-insert-G_DEFINE_TYPE (package
+                                            class
+                                            parent-package
+                                            parent-class)
+  "Insert G_DEFINE_TYPE for PACKAGE and CLASS."
+  (interactive (gnome-c-snippet--read-package-and-class t))
+  (gnome-c-snippet--insert-class-definition package
+                                           class
+                                           parent-package
+                                           parent-class
+                                           nil
+                                           nil))
 
-static void
-" (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self)
-{
-}
-"))
+(defun gnome-c-snippet-insert-G_DEFINE_TYPE_WITH_CODE (package
+                                                      class
+                                                      parent-package
+                                                      parent-class)
+  "Insert G_DEFINE_TYPE_WITH_CODE for PACKAGE and CLASS."
+  (interactive (gnome-c-snippet--read-package-and-class t))
+  (gnome-c-snippet--insert-class-definition package
+                                           class
+                                           parent-package
+                                           parent-class
+                                           nil
+                                           t))
 
-(defun gnome-c-snippet-insert-class-definition (package
-                                               class
-                                               parent-package
-                                               parent-class)
-  "Insert class definition for PACKAGE and CLASS."
+(defun gnome-c-snippet-insert-G_DEFINE_ABSTRACT_TYPE (package
+                                                     class
+                                                     parent-package
+                                                     parent-class)
+  "Insert G_DEFINE_ABSTRACT_TYPE for PACKAGE and CLASS."
   (interactive (gnome-c-snippet--read-package-and-class t))
   (gnome-c-snippet--insert-class-definition package
                                            class
                                            parent-package
                                            parent-class
+                                           t
                                            nil))
 
-(defun gnome-c-snippet-insert-abstract-class-definition (package
-                                                        class
-                                                        parent-package
-                                                        parent-class)
-  "Insert abstract class definition for PACKAGE and CLASS."
+(defun gnome-c-snippet-insert-G_DEFINE_ABSTRACT_TYPE_WITH_CODE (package
+                                                               class
+                                                               parent-package
+                                                               parent-class)
+  "Insert G_DEFINE_ABSTRACT_TYPE_WITH_CODE for PACKAGE and CLASS."
   (interactive (gnome-c-snippet--read-package-and-class t))
   (gnome-c-snippet--insert-class-definition package
                                            class
                                            parent-package
                                            parent-class
+                                           t
                                            t))
 
 (defun gnome-c-snippet-insert-constructor (package class)
@@ -448,15 +632,38 @@ static void
 ")
     (indent-region body-start (point))))
 
+(defun gnome-c-snippet-insert-class-init (package class)
+  "Insert '_class_init' function for PACKAGE and CLASS."
+  (interactive (gnome-c-snippet--read-package-and-class nil))
+  (insert "\
+static void
+" (gnome-c-snippet--format-package_class package class) "_class_init (" (gnome-c-snippet--format-PackageClass package class) "Class *klass)\n")
+    (insert "{
+}
+"))
+
+(defun gnome-c-snippet-insert-init (package class)
+  "Insert '_init' function for PACKAGE and CLASS."
+  (interactive (gnome-c-snippet--read-package-and-class nil))
+  (insert "\
+static void
+" (gnome-c-snippet--format-package_class package class) "_init (" (gnome-c-snippet--format-PackageClass package class) " *self)\n")
+    (insert "{
+}
+"))
+
 (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_TYPE" . gnome-c-snippet-insert-G_DEFINE_TYPE)
+    ("G_DEFINE_TYPE_WITH_CODE" . gnome-c-snippet-insert-G_DEFINE_TYPE_WITH_CODE)
     ("G_DEFINE_ABSTRACT_TYPE" .
-     gnome-c-snippet-insert-abstract-class-definition)
+     gnome-c-snippet-insert-G_DEFINE_ABSTRACT_TYPE)
+    ("G_DEFINE_ABSTRACT_TYPE_WITH_CODE" .
+     gnome-c-snippet-insert-G_DEFINE_ABSTRACT_TYPE_WITH_CODE)
     ("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)
@@ -465,16 +672,31 @@ static void
     ("GObjectClass.dispatch_properties_changed" .
      gnome-c-snippet-insert-dispatch_properties_changed)
     ("GObjectClass.notify" . gnome-c-snippet-insert-notify)
-    ("GObjectClass.constructed" . gnome-c-snippet-insert-constructed)))
+    ("GObjectClass.constructed" . gnome-c-snippet-insert-constructed)
+    ;; Will be overridden by `gnome-c-snippet-insert'.
+    ("_class_init" . gnome-c-snippet-insert-class-init)
+    ;; Will be overridden by `gnome-c-snippet-insert'.
+    ("_init" . gnome-c-snippet-insert-init)))
 
 ;;;###autoload
-(defun gnome-c-snippet-insert (snippet)
+(defun gnome-c-snippet-insert (command)
   (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))))
+   (let ((commands (copy-tree gnome-c-snippet-snippet-commands)))
+     (when (and gnome-c-snippet-package gnome-c-snippet-class)
+       (setcar (assoc "_class_init" commands)
+              (concat (gnome-c-snippet--format-package_class
+                       gnome-c-snippet-package gnome-c-snippet-class)
+                      "_class_init"))
+       (setcar (assoc "_init" commands)
+              (concat (gnome-c-snippet--format-package_class
+                       gnome-c-snippet-package gnome-c-snippet-class)
+                      "_init")))
+     (let* ((name (completing-read "Snippet: " commands nil t))
+           (entry (assoc name commands)))
+       (unless entry
+        (error "Unknown snippet: %s" name))
+       (list (cdr entry)))))
+  (call-interactively command))
 
 (provide 'gnome-c-snippet)