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