xref: /minix3/external/bsd/llvm/dist/clang/tools/clang-format/clang-format.el (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc;;; clang-format.el --- Format code using clang-format
2f4a2713aSLionel Sambuc
3*0a6a1f1dSLionel Sambuc;; Keywords: tools, c
4*0a6a1f1dSLionel Sambuc;; Package-Requires: ((cl-lib "0.3"))
5*0a6a1f1dSLionel Sambuc
6*0a6a1f1dSLionel Sambuc;;; Commentary:
7*0a6a1f1dSLionel Sambuc
8*0a6a1f1dSLionel Sambuc;; This package allows to filter code through clang-format to fix its formatting.
9*0a6a1f1dSLionel Sambuc;; clang-format is a tool that formats C/C++/Obj-C code according to a set of
10*0a6a1f1dSLionel Sambuc;; style options, see <http://clang.llvm.org/docs/ClangFormatStyleOptions.html>.
11*0a6a1f1dSLionel Sambuc;; Note that clang-format 3.4 or newer is required.
12*0a6a1f1dSLionel Sambuc
13*0a6a1f1dSLionel Sambuc;; clang-format.el is available via MELPA and can be installed via
14f4a2713aSLionel Sambuc;;
15*0a6a1f1dSLionel Sambuc;;   M-x package-install clang-format
16*0a6a1f1dSLionel Sambuc;;
17*0a6a1f1dSLionel Sambuc;; when ("melpa" . "http://melpa.org/packages/") is included in
18*0a6a1f1dSLionel Sambuc;; `package-archives'. Alternatively, ensure the directory of this
19*0a6a1f1dSLionel Sambuc;; file is in your `load-path' and add
20*0a6a1f1dSLionel Sambuc;;
21*0a6a1f1dSLionel Sambuc;;   (require 'clang-format)
22*0a6a1f1dSLionel Sambuc;;
23*0a6a1f1dSLionel Sambuc;; to your .emacs configuration.
24*0a6a1f1dSLionel Sambuc
25*0a6a1f1dSLionel Sambuc;; You may also want to bind `clang-format-region' to a key:
26*0a6a1f1dSLionel Sambuc;;
27f4a2713aSLionel Sambuc;;   (global-set-key [C-M-tab] 'clang-format-region)
28f4a2713aSLionel Sambuc
29*0a6a1f1dSLionel Sambuc;;; Code:
30f4a2713aSLionel Sambuc
31*0a6a1f1dSLionel Sambuc(require 'cl-lib)
32*0a6a1f1dSLionel Sambuc(require 'xml)
33f4a2713aSLionel Sambuc
34*0a6a1f1dSLionel Sambuc(defgroup clang-format nil
35*0a6a1f1dSLionel Sambuc  "Format code using clang-format."
36*0a6a1f1dSLionel Sambuc  :group 'tools)
37f4a2713aSLionel Sambuc
38*0a6a1f1dSLionel Sambuc(defcustom clang-format-executable
39*0a6a1f1dSLionel Sambuc  (or (executable-find "clang-format")
40*0a6a1f1dSLionel Sambuc      "clang-format")
41*0a6a1f1dSLionel Sambuc  "Location of the clang-format executable.
42f4a2713aSLionel Sambuc
43*0a6a1f1dSLionel SambucA string containing the name or the full path of the executable."
44*0a6a1f1dSLionel Sambuc  :group 'clang-format
45*0a6a1f1dSLionel Sambuc  :type 'string
46*0a6a1f1dSLionel Sambuc  :risky t)
47*0a6a1f1dSLionel Sambuc
48*0a6a1f1dSLionel Sambuc(defcustom clang-format-style "file"
49*0a6a1f1dSLionel Sambuc  "Style argument to pass to clang-format.
50*0a6a1f1dSLionel Sambuc
51*0a6a1f1dSLionel SambucBy default clang-format will load the style configuration from
52*0a6a1f1dSLionel Sambuca file named .clang-format located in one of the parent directories
53*0a6a1f1dSLionel Sambucof the buffer."
54*0a6a1f1dSLionel Sambuc  :group 'clang-format
55*0a6a1f1dSLionel Sambuc  :type 'string
56*0a6a1f1dSLionel Sambuc  :safe #'stringp)
57*0a6a1f1dSLionel Sambuc(make-variable-buffer-local 'clang-format-style)
58*0a6a1f1dSLionel Sambuc
59*0a6a1f1dSLionel Sambuc(defun clang-format--extract (xml-node)
60*0a6a1f1dSLionel Sambuc  "Extract replacements and cursor information from XML-NODE."
61*0a6a1f1dSLionel Sambuc  (unless (and (listp xml-node) (eq (xml-node-name xml-node) 'replacements))
62*0a6a1f1dSLionel Sambuc    (error "Expected <replacements> node"))
63*0a6a1f1dSLionel Sambuc  (let ((nodes (xml-node-children xml-node))
64*0a6a1f1dSLionel Sambuc        replacements
65*0a6a1f1dSLionel Sambuc        cursor)
66*0a6a1f1dSLionel Sambuc    (dolist (node nodes)
67*0a6a1f1dSLionel Sambuc      (when (listp node)
68*0a6a1f1dSLionel Sambuc        (let* ((children (xml-node-children node))
69*0a6a1f1dSLionel Sambuc               (text (car children)))
70*0a6a1f1dSLionel Sambuc          (cl-case (xml-node-name node)
71*0a6a1f1dSLionel Sambuc            ('replacement
72*0a6a1f1dSLionel Sambuc             (let* ((offset (xml-get-attribute-or-nil node 'offset))
73*0a6a1f1dSLionel Sambuc                    (length (xml-get-attribute-or-nil node 'length)))
74*0a6a1f1dSLionel Sambuc               (when (or (null offset) (null length))
75*0a6a1f1dSLionel Sambuc                 (error "<replacement> node does not have offset and length attributes"))
76*0a6a1f1dSLionel Sambuc               (when (cdr children)
77*0a6a1f1dSLionel Sambuc                 (error "More than one child node in <replacement> node"))
78*0a6a1f1dSLionel Sambuc
79*0a6a1f1dSLionel Sambuc               (setq offset (1+ (string-to-number offset)))
80*0a6a1f1dSLionel Sambuc               (setq length (string-to-number length))
81*0a6a1f1dSLionel Sambuc               (push (list offset length text) replacements)))
82*0a6a1f1dSLionel Sambuc            ('cursor
83*0a6a1f1dSLionel Sambuc             (setq cursor (1+ (string-to-number text))))))))
84*0a6a1f1dSLionel Sambuc
85*0a6a1f1dSLionel Sambuc    ;; Sort by decreasing offset, length.
86*0a6a1f1dSLionel Sambuc    (setq replacements (sort (delq nil replacements)
87*0a6a1f1dSLionel Sambuc                             (lambda (a b)
88*0a6a1f1dSLionel Sambuc                               (or (> (car a) (car b))
89*0a6a1f1dSLionel Sambuc                                   (and (= (car a) (car b))
90*0a6a1f1dSLionel Sambuc                                        (> (cadr a) (cadr b)))))))
91*0a6a1f1dSLionel Sambuc
92*0a6a1f1dSLionel Sambuc    (cons replacements cursor)))
93*0a6a1f1dSLionel Sambuc
94*0a6a1f1dSLionel Sambuc(defun clang-format--replace (offset length &optional text)
95*0a6a1f1dSLionel Sambuc  (goto-char offset)
96*0a6a1f1dSLionel Sambuc  (delete-char length)
97*0a6a1f1dSLionel Sambuc  (when text
98*0a6a1f1dSLionel Sambuc    (insert text)))
99*0a6a1f1dSLionel Sambuc
100*0a6a1f1dSLionel Sambuc;;;###autoload
101*0a6a1f1dSLionel Sambuc(defun clang-format-region (start end &optional style)
102*0a6a1f1dSLionel Sambuc  "Use clang-format to format the code between START and END according to STYLE.
103*0a6a1f1dSLionel SambucIf called interactively uses the region or the current statement if there
104*0a6a1f1dSLionel Sambucis no active region.  If no style is given uses `clang-format-style'."
105*0a6a1f1dSLionel Sambuc  (interactive
106*0a6a1f1dSLionel Sambuc   (if (use-region-p)
107*0a6a1f1dSLionel Sambuc       (list (region-beginning) (region-end))
108*0a6a1f1dSLionel Sambuc     (list (point) (point))))
109*0a6a1f1dSLionel Sambuc
110*0a6a1f1dSLionel Sambuc  (unless style
111*0a6a1f1dSLionel Sambuc    (setq style clang-format-style))
112*0a6a1f1dSLionel Sambuc
113*0a6a1f1dSLionel Sambuc  (let ((temp-buffer (generate-new-buffer " *clang-format-temp*"))
114*0a6a1f1dSLionel Sambuc        (temp-file (make-temp-file "clang-format")))
115f4a2713aSLionel Sambuc    (unwind-protect
116*0a6a1f1dSLionel Sambuc        (let (status stderr operations)
117*0a6a1f1dSLionel Sambuc          (setq status
118*0a6a1f1dSLionel Sambuc                (call-process-region
119*0a6a1f1dSLionel Sambuc                 (point-min) (point-max) clang-format-executable
120*0a6a1f1dSLionel Sambuc                 nil `(,temp-buffer ,temp-file) nil
121*0a6a1f1dSLionel Sambuc
122*0a6a1f1dSLionel Sambuc                 "-output-replacements-xml"
123*0a6a1f1dSLionel Sambuc                 "-assume-filename" (or (buffer-file-name) "")
124*0a6a1f1dSLionel Sambuc                 "-style" style
125*0a6a1f1dSLionel Sambuc                 "-offset" (number-to-string (1- start))
126*0a6a1f1dSLionel Sambuc                 "-length" (number-to-string (- end start))
127*0a6a1f1dSLionel Sambuc                 "-cursor" (number-to-string (1- (point)))))
128*0a6a1f1dSLionel Sambuc          (setq stderr
129*0a6a1f1dSLionel Sambuc                (with-temp-buffer
130*0a6a1f1dSLionel Sambuc                  (insert-file-contents temp-file)
131*0a6a1f1dSLionel Sambuc                  (when (> (point-max) (point-min))
132*0a6a1f1dSLionel Sambuc                    (insert ": "))
133f4a2713aSLionel Sambuc                  (buffer-substring-no-properties
134*0a6a1f1dSLionel Sambuc                   (point-min) (line-end-position))))
135*0a6a1f1dSLionel Sambuc
136*0a6a1f1dSLionel Sambuc          (cond
137*0a6a1f1dSLionel Sambuc           ((stringp status)
138*0a6a1f1dSLionel Sambuc            (error "(clang-format killed by signal %s%s)" status stderr))
139*0a6a1f1dSLionel Sambuc           ((not (equal 0 status))
140*0a6a1f1dSLionel Sambuc            (error "(clang-format failed with code %d%s)" status stderr))
141*0a6a1f1dSLionel Sambuc           (t (message "(clang-format succeeded%s)" stderr)))
142*0a6a1f1dSLionel Sambuc
143*0a6a1f1dSLionel Sambuc          (with-current-buffer temp-buffer
144*0a6a1f1dSLionel Sambuc            (setq operations (clang-format--extract (car (xml-parse-region)))))
145*0a6a1f1dSLionel Sambuc
146*0a6a1f1dSLionel Sambuc          (let ((replacements (car operations))
147*0a6a1f1dSLionel Sambuc                (cursor (cdr operations)))
148*0a6a1f1dSLionel Sambuc            (save-excursion
149*0a6a1f1dSLionel Sambuc              (mapc (lambda (rpl)
150*0a6a1f1dSLionel Sambuc                      (apply #'clang-format--replace rpl))
151*0a6a1f1dSLionel Sambuc                    replacements))
152*0a6a1f1dSLionel Sambuc            (when cursor
153*0a6a1f1dSLionel Sambuc              (goto-char cursor))))
154*0a6a1f1dSLionel Sambuc      (delete-file temp-file)
155*0a6a1f1dSLionel Sambuc      (when (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
156*0a6a1f1dSLionel Sambuc
157*0a6a1f1dSLionel Sambuc;;;###autoload
158*0a6a1f1dSLionel Sambuc(defun clang-format-buffer (&optional style)
159*0a6a1f1dSLionel Sambuc  "Use clang-format to format the current buffer according to STYLE."
160*0a6a1f1dSLionel Sambuc  (interactive)
161*0a6a1f1dSLionel Sambuc  (clang-format-region (point-min) (point-max) style))
162*0a6a1f1dSLionel Sambuc
163*0a6a1f1dSLionel Sambuc;;;###autoload
164*0a6a1f1dSLionel Sambuc(defalias 'clang-format 'clang-format-region)
165*0a6a1f1dSLionel Sambuc
166*0a6a1f1dSLionel Sambuc(provide 'clang-format)
167*0a6a1f1dSLionel Sambuc;;; clang-format.el ends here
168