emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master 30b18d1 2/3: Merge commit 'cce1d8b50b1ceccb80c20398cd659db


From: Daiki Ueno
Subject: [elpa] master 30b18d1 2/3: Merge commit 'cce1d8b50b1ceccb80c20398cd659db3a6348aac' as 'packages/gnome-c-style'
Date: Tue, 19 Jan 2016 06:39:52 +0000

branch: master
commit 30b18d1d6f7deb3b0a1973c87e77490e9a50c818
Merge: 445258b cce1d8b
Author: Daiki Ueno <address@hidden>
Commit: Daiki Ueno <address@hidden>

    Merge commit 'cce1d8b50b1ceccb80c20398cd659db3a6348aac' as 
'packages/gnome-c-style'
---
 packages/gnome-c-style/.gitignore         |    2 +
 packages/gnome-c-style/Makefile           |   16 +
 packages/gnome-c-style/README             |    1 +
 packages/gnome-c-style/README.md          |   94 +++++
 packages/gnome-c-style/gnome-c-align.el   |  536 +++++++++++++++++++++++++++
 packages/gnome-c-style/gnome-c-snippet.el |  565 +++++++++++++++++++++++++++++
 packages/gnome-c-style/gnome-c-style.el   |   75 ++++
 packages/gnome-c-style/gnome-c-tests.el   |  191 ++++++++++
 8 files changed, 1480 insertions(+), 0 deletions(-)

diff --git a/packages/gnome-c-style/.gitignore 
b/packages/gnome-c-style/.gitignore
new file mode 100644
index 0000000..7c5214c
--- /dev/null
+++ b/packages/gnome-c-style/.gitignore
@@ -0,0 +1,2 @@
+*.elc
+
diff --git a/packages/gnome-c-style/Makefile b/packages/gnome-c-style/Makefile
new file mode 100644
index 0000000..571841e
--- /dev/null
+++ b/packages/gnome-c-style/Makefile
@@ -0,0 +1,16 @@
+EMACS ?= emacs
+RM ?= rm
+ELC = gnome-c-align.elc gnome-c-snippet.elc gnome-c-style.elc
+
+all: $(ELC)
+
+%.elc: %.el
+       $(EMACS) -Q -batch --eval "(setq load-path (cons nil load-path))" \
+               -f batch-byte-compile $<
+
+check:
+       $(EMACS) -Q -batch --eval "(setq load-path (cons nil load-path))" \
+               -l ert -l gnome-c-tests.el -f ert-run-tests-batch-and-exit
+
+clean:
+       $(RM) -rf $(ELC)
diff --git a/packages/gnome-c-style/README b/packages/gnome-c-style/README
new file mode 120000
index 0000000..42061c0
--- /dev/null
+++ b/packages/gnome-c-style/README
@@ -0,0 +1 @@
+README.md
\ No newline at end of file
diff --git a/packages/gnome-c-style/README.md b/packages/gnome-c-style/README.md
new file mode 100644
index 0000000..336a462
--- /dev/null
+++ b/packages/gnome-c-style/README.md
@@ -0,0 +1,94 @@
+gnome-c-style
+======
+
+In the C coding style commonly used in GNOME, identifiers are written
+in camel case and function arguments are aligned to the right end.
+That makes it a bit cumbersome to keep your code consistent with the
+style, even with align.el or plugins like yasnippet.
+
+gnome-c-style is an Emacs minor mode intended to help editing C
+source code in that style.  It mainly provides two features: text
+alignment and snippet insersion.
+
+Install
+------
+
+* Type "make"
+* Copy .elc files somewhere in your load-path
+* Add the following lines to ~/.emacs/init.el:
+
+```
+(autoload 'gnome-c-style-mode "gnome-c-style" "GNOME-style C minor mode" t)
+(add-hook 'c-mode-hook 'gnome-c-style-mode)
+```
+
+Usage
+------
+
+| Key         | Command                                                   |
+--------------|-----------------------------------------------------------|
+| C-c C-g a   | Align argument list at the current point                  |
+| C-c C-g r   | Align function declarations in the current region         |
+| C-c C-g C-g | Compute optimal alignment columns from the current region |
+| C-c C-g g   | Guess alignment columns from the current region           |
+| C-c C-g s   | Set alignment column to the current point                 |
+| C-c C-g c   | Insert ```module_object```                                |
+| C-c C-g C   | Insert ```MODULE_OBJECT```                                |
+| C-c C-g C-c | Insert ```ModuleObject```                                 |
+| C-c C-g s   | Insert custom snippet                                     |
+
+Example
+------
+
+If you have the following code in a header file:
+```c
+GGpgCtx *g_gpg_ctx_new (GError **error);
+
+typedef void (*GGpgProgressCallback) (gpointer user_data,
+                                      const gchar *what,
+                                      gint type,
+                                      gint current,
+                                      gint total);
+
+void g_gpg_ctx_set_progress_callback (GGpgCtx *ctx,
+                                      GGpgProgressCallback callback,
+                                      gpointer user_data,
+                                      GDestroyNotify destroy_data);
+void g_gpg_ctx_add_signer (GGpgCtx *ctx, GGpgKey *key);
+guint g_gpg_ctx_get_n_signers (GGpgCtx *ctx);
+GGpgKey *g_gpg_ctx_get_signer (GGpgCtx *ctx, guint index);
+void g_gpg_ctx_clear_signers (GGpgCtx *ctx);
+```
+
+Mark the region, type ```C-c C-g C-g```, and you will see the optimum
+alignment columns:
+
+```
+identifier-start: 9, arglist-start: 41, arglist-identifier-start: 63
+```
+
+Then, mark the region again, type ```C-c C-g r```, and you will get
+the code aligned:
+
+```c
+GGpgCtx *g_gpg_ctx_new                   (GError             **error);
+
+typedef void (*GGpgProgressCallback) (gpointer user_data,
+                                      const gchar *what,
+                                      gint type,
+                                      gint current,
+                                      gint total);
+
+void     g_gpg_ctx_set_progress_callback (GGpgCtx             *ctx,
+                                          GGpgProgressCallback callback,
+                                          gpointer             user_data,
+                                          GDestroyNotify       destroy_data);
+void     g_gpg_ctx_add_signer            (GGpgCtx             *ctx,
+                                          GGpgKey             *key);
+guint    g_gpg_ctx_get_n_signers         (GGpgCtx             *ctx);
+GGpgKey *g_gpg_ctx_get_signer            (GGpgCtx             *ctx,
+                                          guint                index);
+void     g_gpg_ctx_clear_signers         (GGpgCtx             *ctx);
+```
+
+Note that ```typedef``` is skipped as it is not a function declaration.
diff --git a/packages/gnome-c-style/gnome-c-align.el 
b/packages/gnome-c-style/gnome-c-align.el
new file mode 100644
index 0000000..64b8178
--- /dev/null
+++ b/packages/gnome-c-style/gnome-c-align.el
@@ -0,0 +1,536 @@
+;; gnome-c-align.el --- GNOME-style code alignment -*- lexical-binding: t; -*-
+;; Copyright (C) 2016 Free Software Foundation, Inc.
+
+;; Author: Daiki Ueno <address@hidden>
+;; 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
+;; <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'cc-mode)
+(require 'cl-lib)
+
+(defcustom gnome-c-align-max-column 80
+  "Maximum number of columns per line."
+  :type '(choice (integer :tag "Columns")
+                (const :tag "No wrap"))
+  :group 'gnome-c-style)
+
+(defvar gnome-c-align-identifier-start-column nil)
+(make-variable-buffer-local 'gnome-c-align-identifier-start-column)
+
+(defvar gnome-c-align-arglist-start-column nil)
+(make-variable-buffer-local 'gnome-c-align-arglist-start-column)
+
+(defvar gnome-c-align-arglist-identifier-start-column nil)
+(make-variable-buffer-local 'gnome-c-align-arglist-identifier-start-column)
+
+(cl-defstruct (gnome-c-align--argument
+              (:constructor nil)
+              (:constructor gnome-c-align--make-argument (type-start
+                                                          type-identifier-end
+                                                          type-end
+                                                          identifier-start
+                                                          identifier-end))
+              (:copier nil)
+              (:predicate nil))
+  (type-start nil :read-only t)
+  (type-identifier-end nil :read-only t)
+  (type-end nil :read-only t)
+  (identifier-start nil :read-only t)
+  (identifier-end nil :read-only t))
+
+(defun gnome-c-align--marker-column (marker)
+  (save-excursion
+    (goto-char marker)
+    (current-column)))
+
+(defun gnome-c-align--indent-to-column (column)
+  ;; Prefer 'char **foo' than 'char ** foo'
+  (when (looking-back "\\*+" nil t)
+    (setq column (- column (- (match-end 0) (match-beginning 0))))
+    (goto-char (match-beginning 0)))
+  ;; FIXME: should respect indent-tabs-mode?
+  (let (indent-tabs-mode)
+    (indent-to-column column)))
+
+(defun gnome-c-align--argument-type-width (arg)
+  (- (gnome-c-align--marker-column (gnome-c-align--argument-type-end arg))
+     (gnome-c-align--marker-column (gnome-c-align--argument-type-start arg))))
+
+(defun gnome-c-align--argument-type-identifier-width (arg)
+  (- (gnome-c-align--marker-column
+      (gnome-c-align--argument-type-identifier-end arg))
+     (gnome-c-align--marker-column
+      (gnome-c-align--argument-type-start arg))))
+
+(defun gnome-c-align--arglist-identifier-start-column (arglist start-column)
+  (let ((max-type-identifier-width
+        (apply #'max
+               0
+               (mapcar #'gnome-c-align--argument-type-identifier-width
+                       arglist)))
+       (max-extra-width
+        (apply #'max
+               0
+               (mapcar
+                (lambda (argument)
+                  (- (gnome-c-align--argument-type-end argument)
+                     (gnome-c-align--argument-type-identifier-end argument)))
+                arglist))))
+    (+ start-column max-type-identifier-width max-extra-width)))
+
+(defun gnome-c-align--argument-identifier-width (argument)
+  (if (gnome-c-align--argument-identifier-start argument)
+      (- (gnome-c-align--marker-column
+         (gnome-c-align--argument-identifier-end argument))
+        (gnome-c-align--marker-column
+         (gnome-c-align--argument-identifier-start argument)))
+    0))
+
+(defun gnome-c-align--arglist-identifier-width (arglist)
+  (apply #'max 0 (mapcar #'gnome-c-align--argument-identifier-width arglist)))
+
+(defun gnome-c-align--normalize-arglist-region (arglist beg end)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      (while (re-search-forward "\\s-+" nil t)
+       (replace-match " "))
+      (goto-char (point-min))
+      (while (re-search-forward "\\s-*," nil t)
+       (replace-match ",\n"))
+      (goto-char (point-min))
+      (delete-trailing-whitespace)
+      ;; Remove whitespace at the beginning of line
+      (goto-char (point-min))
+      (while (re-search-forward "^\\s-+" nil t)
+       (replace-match ""))
+      ;; Remove empty lines
+      (goto-char (point-min))
+      (delete-matching-lines "^$")
+      ;; 'int * * * foo' -> 'int ***foo'
+      (dolist (argument arglist)
+       (goto-char (gnome-c-align--argument-type-end argument))
+       (while (re-search-backward
+               "\\(\\*+\\)\\s-+"
+               (gnome-c-align--argument-type-identifier-end argument)
+               t)
+         (replace-match "\\1"))
+       (when (gnome-c-align--argument-identifier-start argument)
+         (goto-char (gnome-c-align--argument-identifier-start argument))
+         (if (looking-back "\\* " nil)
+             (delete-char -1)))
+       (goto-char (gnome-c-align--argument-type-end argument))))))
+
+(defun gnome-c-align--parse-arglist (beg end)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (let (type-start
+           type-identifier-end
+           type-end
+           identifier-start
+           identifier-end
+           arglist
+           last-token-start)
+       (goto-char (point-max))
+       (while (not (bobp))
+         (c-backward-syntactic-ws)
+         (setq identifier-end (point-marker))
+         ;; Array argument, such as 'int a[]'
+         (if (eq (preceding-char) ?\])
+             (c-backward-sexp))
+         (c-backward-token-2)
+         (setq identifier-start (point-marker))
+         (c-backward-syntactic-ws)
+         (if (or (bobp) (eq (preceding-char) ?,))
+             (progn
+               ;; Identifier is omitted, or '...'.
+               (setq type-start identifier-start
+                     type-identifier-end identifier-end
+                     type-end identifier-end
+                     identifier-start nil
+                     identifier-end nil)
+               (c-backward-token-2))
+           (setq type-end (point-marker)
+                 last-token-start type-end)
+           (while (and (not (bobp))
+                       (progn
+                         (c-backward-token-2)
+                         (unless (eq (char-after) ?,)
+                           (setq last-token-start (point-marker)))))
+             (c-backward-syntactic-ws))
+           (setq type-start last-token-start)
+           (save-excursion
+             (goto-char type-end)
+             (skip-chars-backward "* " type-start)
+             (c-backward-syntactic-ws)
+             (setq type-identifier-end (point-marker))))
+         (push (gnome-c-align--make-argument type-start
+                                             type-identifier-end
+                                             type-end
+                                             identifier-start
+                                             identifier-end)
+               arglist))
+       arglist))))
+
+;;;###autoload
+(defun gnome-c-align-arglist-at-point (&optional identifier-start-column)
+  "Reformat argument list at point, aligning argument to the right end."
+  (interactive)
+  (save-excursion
+    (let* (start-column arglist)
+      (cl-destructuring-bind (beg end)
+         (gnome-c-align--arglist-region-at-point (point))
+       (goto-char beg)
+       (setq start-column (current-column))
+       (save-restriction
+         (narrow-to-region beg end)
+         (setq arglist (gnome-c-align--parse-arglist (point-min) (point-max)))
+         (gnome-c-align--normalize-arglist-region
+          arglist (point-min) (point-max))
+         (unless identifier-start-column
+           (setq identifier-start-column
+                 (gnome-c-align--arglist-identifier-start-column arglist 0)))
+         (dolist (argument arglist)
+           (goto-char (gnome-c-align--argument-type-start argument))
+           (let ((column (if (bobp) 0 start-column)))
+             (when (not (bobp))
+               (gnome-c-align--indent-to-column start-column))
+             (when (gnome-c-align--argument-identifier-start argument)
+               (setq column (+ column identifier-start-column))
+               (goto-char (gnome-c-align--argument-identifier-start argument))
+               (gnome-c-align--indent-to-column column)))))))))
+
+(cl-defstruct (gnome-c-align--decl
+              (:constructor nil)
+              (:constructor gnome-c-align--make-decl (start
+                                                      end
+                                                      identifier-start
+                                                      identifier-end
+                                                      arglist-start
+                                                      arglist-end
+                                                      arglist))
+              (:copier nil)
+              (:predicate nil))
+  (start nil :read-only t)
+  (end nil :read-only t)
+  (identifier-start nil :read-only t)
+  (identifier-end nil :read-only t)
+  (arglist-start nil :read-only t)
+  (arglist-end nil :read-only t)
+  (arglist nil :read-only t))
+
+(defun gnome-c-align--decls-identifier-start-column (decls start-column)
+  (apply #'max
+        start-column
+        (delq nil
+              (mapcar
+               (lambda (decl)
+                 (let ((decl-column
+                        (+ start-column
+                           (gnome-c-align--marker-column
+                            (gnome-c-align--decl-identifier-start decl)))))
+                   (if (and gnome-c-align-max-column
+                            (> decl-column gnome-c-align-max-column))
+                       nil
+                     decl-column)))
+               decls))))
+
+(defun gnome-c-align--decl-identifier-width (decl)
+  (- (gnome-c-align--marker-column
+      (gnome-c-align--decl-identifier-end decl))
+     (gnome-c-align--marker-column
+      (gnome-c-align--decl-identifier-start decl))))
+
+(defun gnome-c-align--decls-arglist-start-column (decls start-column)
+  (let ((arglist-width
+        (+ (gnome-c-align--decls-arglist-identifier-start-column decls 0)
+           (gnome-c-align--decls-arglist-identifier-width decls)
+           (length ");"))))
+    (apply #'max
+          start-column
+          (delq nil
+                (mapcar
+                 (lambda (decl)
+                   (let ((decl-column
+                          (+ start-column
+                             (gnome-c-align--decl-identifier-width decl)
+                             1)))
+                     (if (and gnome-c-align-max-column
+                              (> (+ decl-column arglist-width)
+                                 gnome-c-align-max-column))
+                         nil
+                       decl-column)))
+                 decls)))))
+
+(defun gnome-c-align--decls-arglist-identifier-width (decls)
+  (apply #'max 0 (mapcar (lambda (decl)
+                          (gnome-c-align--arglist-identifier-width
+                           (gnome-c-align--decl-arglist decl)))
+                        decls)))
+
+(defun gnome-c-align--decls-arglist-identifier-start-column (decls 
start-column)
+  (apply #'max 0 (mapcar (lambda (decl)
+                          ;; FIXME: should wrap lines inside argument list?
+                          (gnome-c-align--arglist-identifier-start-column
+                           (gnome-c-align--decl-arglist decl)
+                           start-column))
+                        decls)))
+
+(defun gnome-c-align--parse-decl (beg end)
+  ;; Parse at most one func declaration found in BEG END.
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (let (arglist-start
+           arglist-end
+           identifier-start
+           identifier-end
+           vfunc-p)
+       (goto-char (point-min))
+       (c-forward-syntactic-ws)
+       (unless (looking-at
+                "typedef\\|#\\|G_\\(?:DECLARE\\|DEFINE\\)")
+         (while (and (not (eobp))
+                     (not (eq (char-after) ?\()))
+           (c-forward-token-2)
+           (c-forward-syntactic-ws))
+         ;; Identifier is vfunc.
+         (when (looking-at "(\\s-*\\*")
+           (c-forward-sexp)
+           (c-forward-syntactic-ws)
+           (setq vfunc-p t))
+         (when (eq (char-after) ?\()
+           (setq arglist-start (point-marker))
+           (c-backward-syntactic-ws)
+           (setq identifier-end (point-marker))
+           (if vfunc-p
+               (c-backward-sexp)
+             (c-backward-token-2))
+           (setq identifier-start (point-marker))
+           (goto-char arglist-start)
+           (c-forward-sexp)
+           (setq arglist-end (point-marker))
+           (gnome-c-align--make-decl beg end
+                                     identifier-start identifier-end
+                                     arglist-start arglist-end
+                                     (gnome-c-align--parse-arglist
+                                      (1+ arglist-start)
+                                      (1- arglist-end)))))))))
+
+(defun gnome-c-align--normalize-decl (decl)
+  (save-excursion
+    ;; Replace newlines with a space
+    (save-restriction
+      ;; Ignore lines before identifier-start
+      (goto-char (gnome-c-align--decl-identifier-start decl))
+      (beginning-of-line)
+      (narrow-to-region (point)
+                       (gnome-c-align--decl-arglist-end decl))
+      (goto-char (point-min))
+      (while (re-search-forward "\n" nil t)
+       (replace-match " ")))
+    ;; Replace consequent spaces with a space
+    (save-restriction
+      ;; Ignore lines before identifier-start
+      (goto-char (gnome-c-align--decl-identifier-start decl))
+      (beginning-of-line)
+      (narrow-to-region (point)
+                       (gnome-c-align--decl-arglist-end decl))
+      (goto-char (point-min))
+      (while (re-search-forward "\\s-+" nil t)
+       (replace-match " ")))
+    (goto-char (gnome-c-align--decl-identifier-start decl))
+    (if (looking-back "\\* " nil)
+       (delete-char -1))
+    ;; Normalize the argument list
+    (gnome-c-align--normalize-arglist-region
+     (gnome-c-align--decl-arglist decl)
+     (gnome-c-align--decl-arglist-start decl)
+     (gnome-c-align--decl-arglist-end decl))))
+
+(defun gnome-c-align--arglist-region-at-point (point)
+  (save-excursion
+    (let (start)
+      (goto-char point)
+      (c-beginning-of-statement-1)
+      (c-backward-syntactic-ws)
+      (unless (eq ?\( (preceding-char))
+       (error "No containing argument list"))
+      (setq start (point))
+      (backward-char)
+      (condition-case nil
+         (c-forward-sexp)
+       (error
+        (error "No closing parenthesis")))
+      (backward-char)
+      (list start (point)))))
+
+;;;###autoload
+(defun gnome-c-align-set-column (symbol)
+  "Set alignment column of SYMBOL."
+  (interactive
+   (let ((symbol-name (completing-read "Symbol to change: "
+                                      '("identifier-start"
+                                        "arglist-start"
+                                        "arglist-identifier-start")
+                                      nil t)))
+     (list (intern (format "gnome-c-align-%s-column" symbol-name)))))
+  (set symbol (current-column)))
+
+(defun gnome-c-align--scan-decls (beg end)
+  (save-excursion
+    (save-restriction
+      (narrow-to-region beg end)
+      (goto-char (point-min))
+      (let (decls)
+       (while (not (eobp))
+         (let (decl-start decl-end decl)
+           (c-forward-syntactic-ws)
+           (setq decl-start (point-marker))
+           (c-end-of-statement)
+           (setq decl-end (point-marker))
+           (setq decl (gnome-c-align--parse-decl decl-start decl-end))
+           (when decl
+             (push decl decls))))
+       decls))))
+
+(defun gnome-c-align--guess-optimal-columns (beg end)
+  (let ((buffer (current-buffer))
+       decls)
+    (with-temp-buffer
+      (insert-buffer-substring-no-properties buffer beg end)
+      (c-mode)
+      (setq decls (gnome-c-align--scan-decls (point-min) (point-max)))
+      (mapc #'gnome-c-align--normalize-decl decls)
+      (let* ((identifier-start-column
+             (gnome-c-align--decls-identifier-start-column
+              decls 0))
+            (arglist-start-column
+             (gnome-c-align--decls-arglist-start-column
+              decls identifier-start-column))
+            (arglist-identifier-start-column
+             (gnome-c-align--decls-arglist-identifier-start-column
+              decls (+ (length "(") arglist-start-column))))
+       (list (cons 'identifier-start-column
+                   identifier-start-column)
+             (cons 'arglist-start-column
+                   arglist-start-column)
+             (cons 'arglist-identifier-start-column
+                   arglist-identifier-start-column))))))
+
+;;;###autoload
+(defun gnome-c-align-guess-optimal-columns (beg end)
+  "Compute the optimal alignment rule from the declarations in BEG and END.
+
+This sets `gnome-c-align-identifier-start-column',
+`gnome-c-align-arglist-start-column', and
+`gnome-c-align-arglist-identifier-start-column'."
+  (interactive "r")
+  (let ((columns (gnome-c-align--guess-optimal-columns beg end)))
+    (setq gnome-c-align-identifier-start-column
+         (cdr (assq 'identifier-start-column columns))
+         gnome-c-align-arglist-start-column
+         (cdr (assq 'arglist-start-column columns))
+         gnome-c-align-arglist-identifier-start-column
+         (cdr (assq 'arglist-identifier-start-column columns)))
+    (message
+     "identifier-start: %d, arglist-start: %d, arglist-identifier-start: %d"
+     gnome-c-align-identifier-start-column
+     gnome-c-align-arglist-start-column
+     gnome-c-align-arglist-identifier-start-column)))
+
+;;;###autoload
+(defun gnome-c-align-guess-columns (beg end)
+  "Guess the existing alignment rule from the declarations in BEG and END.
+
+This sets `gnome-c-align-identifier-start-column',
+`gnome-c-align-arglist-start-column', and
+`gnome-c-align-arglist-identifier-start-column'."
+  (interactive "r")
+  (let ((decls (gnome-c-align--scan-decls beg end))
+       arglist)
+    (unless decls
+      (error "No function declaration in the region"))
+    (setq arglist (gnome-c-align--parse-arglist
+                  (1+ (gnome-c-align--decl-arglist-start (car decls)))
+                  (1- (gnome-c-align--decl-arglist-end (car decls)))))
+    (unless arglist
+      (error "Empty argument list"))
+    (unless (gnome-c-align--argument-identifier-start (car arglist))
+      (error "No identifier in the argument list"))
+    (setq gnome-c-align-identifier-start-column
+         (gnome-c-align--marker-column
+          (gnome-c-align--decl-identifier-start (car decls)))
+         gnome-c-align-arglist-start-column
+         (gnome-c-align--marker-column
+          (gnome-c-align--decl-arglist-start (car decls)))
+         gnome-c-align-arglist-identifier-start-column
+         (gnome-c-align--marker-column
+          (gnome-c-align--argument-identifier-start (car arglist))))
+    (message
+     "identifier-start: %d, arglist-start: %d, arglist-identifier-start: %d"
+     gnome-c-align-identifier-start-column
+     gnome-c-align-arglist-start-column
+     gnome-c-align-arglist-identifier-start-column)))
+
+;;;###autoload
+(defun gnome-c-align-decls-region (beg end)
+  "Reformat function declarations in the region between BEG and END."
+  (interactive "r")
+  (save-excursion
+    (let (decls)
+      (save-restriction
+       (narrow-to-region beg end)
+       (unless (and gnome-c-align-identifier-start-column
+                    gnome-c-align-arglist-start-column
+                    gnome-c-align-arglist-identifier-start-column)
+         (let ((columns (gnome-c-align--guess-optimal-columns beg end)))
+           (unless gnome-c-align-identifier-start-column
+             (setq gnome-c-align-identifier-start-column
+                   (cdr (assq 'identifier-start-column columns))))
+           (unless gnome-c-align-arglist-start-column
+             (setq gnome-c-align-arglist-start-column
+                   (cdr (assq 'arglist-start-column columns))))
+           (unless gnome-c-align-arglist-identifier-start-column
+             (setq gnome-c-align-arglist-identifier-start-column
+                   (cdr (assq 'arglist-identifier-start-column columns))))))
+       (setq decls (gnome-c-align--scan-decls beg end))
+       (mapc #'gnome-c-align--normalize-decl decls)
+       (dolist (decl decls)
+         (goto-char (gnome-c-align--decl-identifier-start decl))
+         (gnome-c-align--indent-to-column
+          gnome-c-align-identifier-start-column)
+         (goto-char (gnome-c-align--decl-identifier-end decl))
+         (when (>= (current-column) gnome-c-align-arglist-start-column)
+           (insert "\n"))
+         (goto-char (gnome-c-align--decl-arglist-start decl))
+         (gnome-c-align--indent-to-column
+          gnome-c-align-arglist-start-column)
+         (forward-char)
+         (gnome-c-align-arglist-at-point
+          (- (- gnome-c-align-arglist-identifier-start-column
+                (length "("))
+             gnome-c-align-arglist-start-column)))))))
+
+(provide 'gnome-c-align)
+
+;;; gnome-c-align.el ends here
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 0000000..ed36336
--- /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 <address@hidden>
+;; 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
+;; <http://www.gnu.org/licenses/>.
+
+;;; 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
diff --git a/packages/gnome-c-style/gnome-c-style.el 
b/packages/gnome-c-style/gnome-c-style.el
new file mode 100644
index 0000000..589de3c
--- /dev/null
+++ b/packages/gnome-c-style/gnome-c-style.el
@@ -0,0 +1,75 @@
+;;; gnome-c-style.el --- minor mode for editing GNOME-style C source code -*- 
lexical-binding: t; -*-
+;; Copyright (C) 2016 Free Software Foundation, Inc.
+
+;; Author: Daiki Ueno <address@hidden>
+;; Keywords: GNOME, C, coding style
+;; Version: 0.1
+;; Maintainer: Daiki Ueno <address@hidden>
+
+;; 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
+;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides a minor mode to help editing C source code
+;; in the GNOME C coding style:
+;;
+;; 
<https://developer.gnome.org/programming-guidelines/stable/c-coding-style.html.en#header-files>
+;; 
<https://developer.gnome.org/programming-guidelines/stable/c-coding-style.html.en#functions>
+;;
+;; It basically provides two functions: code alignment and snippet
+;; insertion.  To align code, use `gnome-c-style-align-region' to
+;; line-up multiple function declarations in region, and
+;; `gnome-c-style-align-at-point' to line-up arguments in the argument
+;; list at point.
+;;
+;; To insert code snippet, use `gnome-c-snippet-insert'.  The command
+;; will let you choose a template to be inserted.  This package also
+;; provide commands to insert package/class names in upper case,
+;; capital case, and lower case.  For complete list of commands, do
+;; M-x describe-bindings.
+
+;;; Code:
+
+(require 'gnome-c-align)
+(require 'gnome-c-snippet)
+
+(defgroup gnome-c-style nil
+  "GNOME-style C source code editing"
+  :prefix "gnome-c-"
+  :group 'c)
+
+(defvar gnome-c-style-mode-map
+  (let ((keymap (make-sparse-keymap)))
+    (define-key keymap "\C-c\C-ga" 'gnome-c-align-arglist-at-point)
+    (define-key keymap "\C-c\C-gr" 'gnome-c-align-decls-region)
+    (define-key keymap "\C-c\C-gf" 'gnome-c-align-set-column)
+    (define-key keymap "\C-c\C-gg" 'gnome-c-align-guess-columns)
+    (define-key keymap "\C-c\C-g\C-g" 'gnome-c-align-guess-optimal-columns)
+    (define-key keymap "\C-c\C-gc" 'gnome-c-snippet-insert-package_class)
+    (define-key keymap "\C-c\C-gC" 'gnome-c-snippet-insert-PACKAGE_CLASS)
+    (define-key keymap "\C-c\C-g\C-c" 'gnome-c-snippet-insert-PackageClass)
+    (define-key keymap "\C-c\C-gs" 'gnome-c-snippet-insert)
+    keymap))
+
+;;;###autoload
+(define-minor-mode gnome-c-style-mode
+  "A minor-mode for editing GNOME-style C source code."
+  nil " GNOME" gnome-c-style-mode-map)
+
+(provide 'gnome-c-style)
+
+;;; gnome-c-style.el ends here
diff --git a/packages/gnome-c-style/gnome-c-tests.el 
b/packages/gnome-c-style/gnome-c-tests.el
new file mode 100644
index 0000000..3b48463
--- /dev/null
+++ b/packages/gnome-c-style/gnome-c-tests.el
@@ -0,0 +1,191 @@
+(require 'gnome-c-align)
+
+(defconst gnome-c-test-program-1 "\
+GGpgCtx *g_gpg_ctx_new (GError **error);
+
+typedef void (*GGpgProgressCallback) (gpointer user_data,
+                                      const gchar *what,
+                                      gint type,
+                                      gint current,
+                                      gint total);
+
+void g_gpg_ctx_set_progress_callback (GGpgCtx *ctx,
+                                      GGpgProgressCallback callback,
+                                      gpointer user_data,
+                                      GDestroyNotify destroy_data);
+void g_gpg_ctx_add_signer (GGpgCtx *ctx, GGpgKey *key);
+guint g_gpg_ctx_get_n_signers (GGpgCtx *ctx);
+GGpgKey *g_gpg_ctx_get_signer (GGpgCtx *ctx, guint index);
+void g_gpg_ctx_clear_signers (GGpgCtx *ctx);
+")
+
+(defconst gnome-c-test-program-1-aligned "\
+GGpgCtx *g_gpg_ctx_new                   (GError              **error);
+
+typedef void (*GGpgProgressCallback) (gpointer user_data,
+                                      const gchar *what,
+                                      gint type,
+                                      gint current,
+                                      gint total);
+
+void     g_gpg_ctx_set_progress_callback (GGpgCtx              *ctx,
+                                          GGpgProgressCallback  callback,
+                                          gpointer              user_data,
+                                          GDestroyNotify        destroy_data);
+void     g_gpg_ctx_add_signer            (GGpgCtx              *ctx,
+                                          GGpgKey              *key);
+guint    g_gpg_ctx_get_n_signers         (GGpgCtx              *ctx);
+GGpgKey *g_gpg_ctx_get_signer            (GGpgCtx              *ctx,
+                                          guint                 index);
+void     g_gpg_ctx_clear_signers         (GGpgCtx              *ctx);
+")
+
+(defconst gnome-c-test-program-2 "\
+GDK_AVAILABLE_IN_3_16
+const gchar **          gtk_widget_list_action_prefixes (GtkWidget             
*widget);
+")
+
+(defconst gnome-c-test-program-3 "\
+  /* overridable methods */
+  void       (*set_property)            (GObject        *object,
+                                         guint           property_id,
+                                         const GValue   *value,
+                                         GParamSpec     *pspec);
+  void       (*get_property)            (GObject        *object,
+                                         guint           property_id,
+                                         GValue         *value,
+                                         GParamSpec     *pspec);
+")
+
+(defconst gnome-c-test-program-4 "\
+FOO_AVAILABLE_IN_ALL
+int foo (struct foo ***a, int b, ...) G_GNUC_CONST;
+")
+
+(defconst gnome-c-test-program-4-aligned "\
+FOO_AVAILABLE_IN_ALL
+int foo (struct foo ***a,
+         int           b,
+         ...) G_GNUC_CONST;
+")
+
+(defconst gnome-c-test-program-5 "\
+int  * bar (const char * const *  * a, int b);
+")
+
+(defconst gnome-c-test-program-5-aligned "\
+int *bar (const char * const **a,
+          int                  b);
+")
+
+(defconst gnome-c-test-program-6 "\
+int foo (char **a, int b);
+type_1234567890 bar (char a, int b);
+int identifier_1234567890 (double a, double b);
+")
+
+(defconst gnome-c-test-program-6-aligned-1 "\
+int             foo
+                (char **a,
+                 int    b);
+type_1234567890 bar
+                (char   a,
+                 int    b);
+int             identifier_1234567890
+                (double a,
+                 double b);
+")
+
+(defconst gnome-c-test-program-6-aligned-2 "\
+int             foo (char **a,
+                     int    b);
+type_1234567890 bar (char   a,
+                     int    b);
+int             identifier_1234567890
+                    (double a,
+                     double b);
+")
+
+(ert-deftest gnome-c-test-align--guess-optimal-columns ()
+  "Tests the `gnome-c-align--guess-optimal-columns'."
+  (with-temp-buffer
+    (insert gnome-c-test-program-1)
+    (c-mode)
+    (let* (gnome-c-align-max-column
+          (columns
+           (gnome-c-align--guess-optimal-columns (point-min) (point-max))))
+      (should (= (cdr (assq 'identifier-start-column columns)) 9))
+      (should (= (cdr (assq 'arglist-start-column columns)) 41))
+      (should (= (cdr (assq 'arglist-identifier-start-column columns)) 64)))))
+
+(ert-deftest gnome-c-test-align-region ()
+  "Tests the `gnome-c-align-decls-region'."
+  (with-temp-buffer
+    (insert gnome-c-test-program-1)
+    (c-mode)
+    (let (gnome-c-align-max-column)
+      (gnome-c-align-guess-optimal-columns (point-min) (point-max))
+      (gnome-c-align-decls-region (point-min) (point-max)))
+    (should (equal (buffer-string) gnome-c-test-program-1-aligned))))
+
+(ert-deftest gnome-c-test-align-region-2 ()
+  "Tests the `gnome-c-align-decls-region'."
+  (with-temp-buffer
+    (insert gnome-c-test-program-4)
+    (c-mode)
+    (let (gnome-c-align-max-column)
+      (gnome-c-align-guess-optimal-columns (point-min) (point-max))
+      (gnome-c-align-decls-region (point-min) (point-max)))
+    (should (equal (buffer-string) gnome-c-test-program-4-aligned))))
+
+(ert-deftest gnome-c-test-align-region-3 ()
+  "Tests the `gnome-c-align-decls-region'."
+  (with-temp-buffer
+    (insert gnome-c-test-program-5)
+    (c-mode)
+    (let (gnome-c-align-max-column)
+      (gnome-c-align-guess-optimal-columns (point-min) (point-max))
+      (gnome-c-align-decls-region (point-min) (point-max)))
+    (should (equal (buffer-string) gnome-c-test-program-5-aligned))))
+
+(ert-deftest gnome-c-test-align-region-4 ()
+  "Tests the `gnome-c-align-decls-region', with max columns set."
+  (with-temp-buffer
+    (insert gnome-c-test-program-6)
+    (c-mode)
+    (let ((gnome-c-align-max-column 20))
+      (gnome-c-align-guess-optimal-columns (point-min) (point-max))
+      (gnome-c-align-decls-region (point-min) (point-max)))
+    (should (equal (buffer-string) gnome-c-test-program-6-aligned-1))))
+
+(ert-deftest gnome-c-test-align-region-5 ()
+  "Tests the `gnome-c-align-decls-region', with max columns set."
+  (with-temp-buffer
+    (insert gnome-c-test-program-6)
+    (c-mode)
+    (let ((gnome-c-align-max-column 30))
+      (gnome-c-align-guess-optimal-columns (point-min) (point-max))
+      (gnome-c-align-decls-region (point-min) (point-max)))
+    (should (equal (buffer-string) gnome-c-test-program-6-aligned-2))))
+
+(ert-deftest gnome-c-test-align-guess-columns-1 ()
+  "Tests the `gnome-c-align-guess-columns'."
+  (with-temp-buffer
+    (insert gnome-c-test-program-2)
+    (c-mode)
+    (let (gnome-c-align-max-column)
+      (gnome-c-align-guess-columns (point-min) (point-max)))
+    (should (= gnome-c-align-identifier-start-column 24))
+    (should (= gnome-c-align-arglist-start-column 56))
+    (should (= gnome-c-align-arglist-identifier-start-column 80))))
+
+(ert-deftest gnome-c-test-align-guess-columns-2 ()
+  "Tests the `gnome-c-align-guess-columns'."
+  (with-temp-buffer
+    (insert gnome-c-test-program-3)
+    (c-mode)
+    (let (gnome-c-align-max-column)
+      (gnome-c-align-guess-columns (point-min) (point-max)))
+    (should (= gnome-c-align-identifier-start-column 13))
+    (should (= gnome-c-align-arglist-start-column 40))
+    (should (= gnome-c-align-arglist-identifier-start-column 57))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]