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