(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 "_"))
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)
")
(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)
("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)