1 ;;; gobject-align.el --- GObject C code alignment
2 ;; Copyright (C) 2010,2011 Daiki Ueno <ueno@gnu.org>
4 ;; Author: Daiki Ueno <ueno@gnu.org>
5 ;; Keywords: GObject, C, coding style
7 ;; This file is not part of GNU Emacs.
9 ;; This program is free software: you can redistribute it and/or
10 ;; modify it under the terms of the GNU General Public License as
11 ;; published by the Free Software Foundation, either version 3 of the
12 ;; License, or (at your option) any later version.
14 ;; This program is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ;; General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program. If not, see
21 ;; <http://www.gnu.org/licenses/>.
28 (defvar gobject-align-whitespace
31 (defvar gobject-align-max-line-width 80)
33 (defun gobject-align--make-arg (type-start type-end arg-name-start arg-name-end)
34 (vector type-start type-end arg-name-start arg-name-end))
36 (defun gobject-align--arg-type-start (arg)
39 (defun gobject-align--arg-arg-name-start (arg)
42 (defun gobject-align--arg-type-width (arg)
43 (- (gobject-align--arg-arg-name-start arg)
44 (gobject-align--arg-type-start arg)))
46 (defun gobject-align--arglist-type-column-width (arglist)
50 (setq length (gobject-align--arg-type-width (car arglist)))
53 (setq arglist (cdr arglist)))
56 (defun gobject-align--arglist-arg-name-column-width (arglist)
60 (setq length (- (aref (car arglist) 3) ;arg-name-end
61 (gobject-align--arg-arg-name-start (car arglist))))
64 (setq arglist (cdr arglist)))
67 (defun gobject-align--parse-arglist (beg end)
70 (narrow-to-region beg end)
78 (goto-char (point-min))
79 (while (and (not (eobp))
80 (setq type-start (point-marker))
81 (if (prog1 (re-search-forward
84 (regexp-quote gobject-align-whitespace)
86 (regexp-quote gobject-align-whitespace)
90 (goto-char (match-beginning 0))
91 (goto-char (point-max))))
92 (setq arg-name-end (point-marker))
94 (setq arg-name-start (point-marker))
95 (skip-chars-backward (concat gobject-align-whitespace "*"))
96 (setq type-end (point-marker))
97 (setq arg (gobject-align--make-arg type-start type-end
98 arg-name-start arg-name-end)
99 arglist (cons arg arglist))
103 (defun gobject-align--make-func-decl (type-start type-end
104 func-name-start func-name-end
105 arglist-start arglist-end
108 (vector type-start type-end func-name-start func-name-end
109 arglist-start arglist-end func-decl-end arglist))
111 (defun gobject-align--func-decl-start (func-decl)
114 (defun gobject-align--func-decl-func-name-start (func-decl)
117 (defun gobject-align--func-decl-func-name-end (func-decl)
120 (defun gobject-align--func-decl-arglist-start (func-decl)
123 (defun gobject-align--func-decl-arglist-end (func-decl)
126 (defun gobject-align--func-decl-end (func-decl)
129 (defun gobject-align--func-decl-arglist (func-decl)
132 (defun gobject-align--func-decl-type-width (func-decl)
133 (- (gobject-align--func-decl-func-name-start func-decl)
134 (gobject-align--func-decl-start func-decl)))
136 (defun gobject-align--func-decl-func-name-width (func-decl)
137 (- (gobject-align--func-decl-arglist-start func-decl)
138 (gobject-align--func-decl-func-name-start func-decl)))
140 (defun gobject-align--func-decls-type-column-width (func-decls)
144 (setq length (gobject-align--func-decl-type-width (car func-decls)))
147 (setq func-decls (cdr func-decls)))
150 (defun gobject-align--func-decls-func-name-column-width (func-decls
152 arglist-column-width)
156 (setq length (gobject-align--func-decl-func-name-width (car func-decls)))
158 (if (and (<= (+ start-column
160 arglist-column-width)
161 gobject-align-max-line-width)
164 (setq func-decls (cdr func-decls)))
167 (defun gobject-align--func-decls-arglist-type-column-width (func-decls)
169 arglist-type-column-width)
171 (setq arglist-type-column-width
172 (gobject-align--arglist-type-column-width
173 (gobject-align--func-decl-arglist (car func-decls))))
174 (if (> arglist-type-column-width width)
175 (setq width arglist-type-column-width))
176 (setq func-decls (cdr func-decls)))
179 (defun gobject-align--func-decls-arglist-arg-name-column-width (func-decls)
181 arglist-arg-name-column-width)
183 (setq arglist-arg-name-column-width
184 (gobject-align--arglist-arg-name-column-width
185 (gobject-align--func-decl-arglist (car func-decls))))
186 (if (> arglist-arg-name-column-width width)
187 (setq width arglist-arg-name-column-width))
188 (setq func-decls (cdr func-decls)))
191 (defun gobject-align--parse-func-decl (beg end)
192 ;; Parse one func-decl in BEG END. BEG and END must point to the
193 ;; beginning/end of the func-decl.
196 (narrow-to-region beg end)
197 (goto-char (point-max))
202 ;; foo *bar (baz a) G_GNUC_CONST;
204 (unless (looking-back (concat "["
205 (regexp-quote gobject-align-whitespace)
207 (regexp-quote gobject-align-whitespace)
209 (regexp-quote gobject-align-whitespace)
211 (regexp-quote gobject-align-whitespace)
215 (error "No func-decl at point"))
216 (goto-char (match-beginning 0))
217 ;; foo *bar (baz a) G_GNUC_CONST;
219 (unless (eq (char-before) ?\))
220 (error "No arglist at point"))
221 (setq arglist-end (point-marker))
222 (c-backward-sexp) ;skip arglist
223 ;; foo *bar (baz a) G_GNUC_CONST;
225 (setq arglist-start (point-marker))
226 (skip-chars-backward gobject-align-whitespace)
227 ;; foo *bar (baz a) G_GNUC_CONST;
229 (setq func-name-end (point-marker))
230 ;;(c-backward-token-2)
231 (c-backward-sexp) ;may be either an identifier
233 ;; foo *bar (baz a) G_GNUC_CONST;
235 (setq func-name-start (point-marker))
236 (skip-chars-backward (concat gobject-align-whitespace "*"))
237 ;; foo *bar (baz a) G_GNUC_CONST;
239 (gobject-align--make-func-decl (point-min-marker) (point-marker)
240 func-name-start func-name-end
241 arglist-start arglist-end
243 (gobject-align--parse-arglist
245 (1- arglist-end)))))))
247 (defun gobject-align--normalize-arglist (beg end)
250 (narrow-to-region beg end)
251 (goto-char (point-min))
252 (while (re-search-forward (concat "["
253 (regexp-quote gobject-align-whitespace)
257 (goto-char (point-min))
258 (while (re-search-forward " *, *" nil t)
259 (replace-match ",\n")))))
261 (defun gobject-align--normalize-func-decl (beg end)
264 (narrow-to-region beg end)
265 (goto-char (point-min))
266 (while (re-search-forward (concat "["
267 (regexp-quote gobject-align-whitespace)
270 (replace-match " ")))))
272 (defun gobject-align--indent-identifier-to-column (column)
273 (when (looking-back "\*+" nil t)
274 (setq column (- column (- (match-end 0) (match-beginning 0))))
275 (goto-char (match-beginning 0)))
276 (let (indent-tabs-mode)
277 (indent-to-column column)))
279 (defun gobject-align--expand-region-to-arglist-extent (beg end)
280 (setq beg (save-excursion
282 (c-beginning-of-decl-1)
288 (unless (and (eq (char-before beg) ?\()
289 (eq (char-after end) ?\)))
290 (error "No arglist around point"))
293 (defun gobject-align-arglist-region (beg end &optional type-column-width)
294 "Reformat argument list in the region between BEG and END.
295 It applies proper alignment rule."
296 (interactive (apply #'gobject-align--expand-region-to-arglist-extent
297 (if (region-active-p)
298 (list (region-beginning) (region-end))
299 (list (point) (point)))))
301 (let ((indent-level (progn (goto-char beg) (current-column)))
306 (narrow-to-region beg end)
307 (setq arglist (gobject-align--parse-arglist (point-min) (point-max)))
308 ;; This may move markers in arglist.
309 (gobject-align--normalize-arglist (point-min) (point-max))
310 (unless type-column-width
311 (setq type-column-width (gobject-align--arglist-type-column-width
314 (setq arg (car arglist))
315 (goto-char (gobject-align--arg-type-start arg))
318 (setq column indent-level))
319 (gobject-align--indent-identifier-to-column column)
320 ;; Don't indent for no-arg-name arg.
321 (unless (= (gobject-align--arg-type-start arg)
322 (gobject-align--arg-arg-name-start arg))
323 (setq column (+ column type-column-width))
324 (goto-char (gobject-align--arg-arg-name-start arg))
325 (gobject-align--indent-identifier-to-column column))
326 (setq arglist (cdr arglist)))))))
328 (defun gobject-align-func-decls-region (beg end)
329 "Reformat function declarations in the region between BEG and END.
330 It applies proper alignment rule."
333 (let ((indent-level (save-excursion
335 (skip-chars-forward gobject-align-whitespace)
343 func-name-column-width
344 arglist-type-column-width
345 arglist-arg-name-column-width
349 (narrow-to-region beg end)
350 (goto-char (point-min))
351 (while (search-forward ";" nil t)
352 ;; XXX: Should skip non-func-decl statements.
353 (setq func-decl-end (point-marker))
354 (c-beginning-of-statement-1)
355 (setq func-decl (gobject-align--parse-func-decl (point-marker)
357 func-decls (cons func-decl func-decls))
358 (goto-char func-decl-end))
359 ;; This may move markers in func-decls.
360 (setq pointer func-decls)
362 (setq func-decl (car pointer))
363 (gobject-align--normalize-func-decl
364 (gobject-align--func-decl-start func-decl)
365 (gobject-align--func-decl-end func-decl))
366 (setq pointer (cdr pointer)))
367 (setq type-column-width
368 (gobject-align--func-decls-type-column-width func-decls)
369 arglist-type-column-width
370 (gobject-align--func-decls-arglist-type-column-width func-decls)
371 arglist-arg-name-column-width
372 (gobject-align--func-decls-arglist-arg-name-column-width
375 (+ arglist-type-column-width
376 arglist-arg-name-column-width
378 func-name-column-width
379 (gobject-align--func-decls-func-name-column-width
383 arglist-column-width))
384 (setq pointer func-decls)
386 (setq func-decl (car pointer))
387 (goto-char (gobject-align--func-decl-start func-decl))
388 (setq column indent-level)
389 (gobject-align--indent-identifier-to-column column)
390 ;; Align type column.
391 (setq func-name-width
392 (- (gobject-align--func-decl-func-name-end func-decl)
393 (gobject-align--func-decl-func-name-start func-decl)))
394 (if (> (+ column type-column-width func-name-width)
395 gobject-align-max-line-width)
398 (gobject-align--func-decl-type-width func-decl)))
399 (setq column (+ column type-column-width)))
400 (goto-char (gobject-align--func-decl-func-name-start func-decl))
401 (gobject-align--indent-identifier-to-column column)
402 ;; Align func-name column.
403 (when (> (- (gobject-align--func-decl-func-name-end func-decl)
405 func-name-column-width)
406 (goto-char (gobject-align--func-decl-func-name-end func-decl))
408 (setq column (+ indent-level type-column-width)))
409 (setq column (+ column func-name-column-width))
410 (goto-char (gobject-align--func-decl-arglist-start func-decl))
411 (gobject-align--indent-identifier-to-column column)
413 (gobject-align-arglist-region
415 (1- (gobject-align--func-decl-arglist-end
417 arglist-type-column-width)
418 (setq pointer (cdr pointer)))))))
420 (provide 'gobject-align)
422 ;;; gobject-align.el ends here