Hi all,

Some time ago, I uploaded a package[1] with essentially the same
functionality as tools/clang-format/clang-format.el to the Emacs package
archive MELPA. My version has several usability improvements and it has
been requested[2] that those changes are consolidated with the version in
the cfe tree. I would be happy to sunset my repository if this patch is
accepted and have the MELPA-package point to the cfe version.

* Includes file header/footer as required by MELPA
* Correctly handles buffers that are not associated with a file
* Displays stderr and exit code of clang-format process
* Is customizable via the Emacs customization interface and
file-/directory-local variables

As this is my first patch to this list, feel free to point out any silly
mistakes I did. :)

All the best,
Johann

[1]: https://github.com/kljohann/clang-format.el
[2]: https://github.com/milkypostman/melpa/issues/2202 and https://github
.com/kljohann/clang-format.el/issues/2
Index: tools/clang-format/clang-format.el
===================================================================
--- tools/clang-format/clang-format.el	(revision 224921)
+++ tools/clang-format/clang-format.el	(working copy)
@@ -1,58 +1,127 @@
-;;; Clang-format emacs integration for use with C/Objective-C/C++.
+;;; clang-format.el --- Format code using clang-format
 
-;; This defines a function clang-format-region that you can bind to a key.
-;; A minimal .emacs would contain:
+;; Keywords: tools, c
+;; Package-Requires: ((json "1.3"))
+
+;;; Commentary:
+
+;; This package allows to filter code through clang-format to fix its formatting.
+;; clang-format is a tool that formats C/C++/Obj-C code according to a set of
+;; style options, see <http://clang.llvm.org/docs/ClangFormatStyleOptions.html>.
+;; Note that clang-format 3.4 or newer is required.
+
+;; clang-format.el is available via MELPA and can be installed via
 ;;
-;;   (load "<path-to-clang>/tools/clang-format/clang-format.el")
-;;   (global-set-key [C-M-tab] 'clang-format-region)
+;;   M-x package-install clang-format
 ;;
-;; Depending on your configuration and coding style, you might need to modify
-;; 'style' in clang-format, below.
+;; when ("melpa" . "http://melpa.org/packages/";) is included in
+;; `package-archives'. Alternatively, ensure the directory of this
+;; file is in your `load-path' and add
+;;
+;;   (require 'clang-format)
+;;
+;; to your .emacs configuration.
 
+;; You may also want to bind `clang-format-region' to a key:
+;;
+;;   (global-set-key [C-M-tab] 'clang-format-region)
+
+;;; Code:
+
 (require 'json)
 
-;; *Location of the clang-format binary. If it is on your PATH, a full path name
-;; need not be specified.
-(defvar clang-format-binary "clang-format")
+(defgroup clang-format nil
+  "Format code using clang-format."
+  :group 'tools)
 
-(defun clang-format-region ()
-  "Use clang-format to format the currently active region."
-  (interactive)
-  (let ((beg (if mark-active
-                 (region-beginning)
-               (min (line-beginning-position) (1- (point-max)))))
-        (end (if mark-active
-                 (region-end)
-               (line-end-position))))
-    (clang-format beg end)))
+(defcustom clang-format-executable
+  (or (executable-find "clang-format")
+      "clang-format")
+  "Location of the clang-format executable.
 
-(defun clang-format-buffer ()
-  "Use clang-format to format the current buffer."
-  (interactive)
-  (clang-format (point-min) (point-max)))
+A string containing the name or the full path of the executable."
+  :group 'clang-format
+  :type 'string)
+(put 'clang-format-executable 'risky-local-variable t)
 
-(defun clang-format (begin end)
-  "Use clang-format to format the code between BEGIN and END."
-  (let* ((orig-windows (get-buffer-window-list (current-buffer)))
-         (orig-window-starts (mapcar #'window-start orig-windows))
-         (orig-point (point))
-         (style "file"))
+(defcustom clang-format-style "file"
+  "Style argument to pass to clang-format.
+
+By default clang-format will load the style configuration from
+a file named .clang-format located in one of the parent directories
+of the buffer."
+  :group 'clang-format
+  :type 'string)
+(make-variable-buffer-local 'clang-format-style)
+(put 'clang-format-style 'safe-local-variable #'stringp)
+
+;;;###autoload
+(defun clang-format-region (start end &optional style)
+  "Use clang-format to format the code between START and END according to STYLE.
+If called interactively uses the region or the current buffer if there
+is no active region.  If no style is given uses `clang-format-style'."
+  (interactive
+   (if (use-region-p)
+       (list (region-beginning) (region-end))
+     (list (point-min) (point-max))))
+
+  (unless style
+    (setq style clang-format-style))
+
+  (let* ((temp-file (make-temp-file "clang-format"))
+         (keep-stderr (list t temp-file))
+         (window-starts
+          (mapcar (lambda (w) (list w (window-start w)))
+                  (get-buffer-window-list)))
+         (status)
+         (stderr)
+         (json))
+
     (unwind-protect
-        (call-process-region (point-min) (point-max) clang-format-binary
-                             t (list t nil) nil
-                             "-offset" (number-to-string (1- begin))
-                             "-length" (number-to-string (- end begin))
-                             "-cursor" (number-to-string (1- (point)))
-                             "-assume-filename" (buffer-file-name)
-                             "-style" style)
-      (goto-char (point-min))
-      (let ((json-output (json-read-from-string
-                           (buffer-substring-no-properties
-                             (point-min) (line-beginning-position 2)))))
-        (delete-region (point-min) (line-beginning-position 2))
-        (goto-char (1+ (cdr (assoc 'Cursor json-output))))
-        (dotimes (index (length orig-windows))
-          (set-window-start (nth index orig-windows)
-                            (nth index orig-window-starts)))))))
+        (setq status
+              (call-process-region
+               (point-min) (point-max) clang-format-executable
+               'delete keep-stderr nil
 
+               "-assume-filename" (or (buffer-file-name) "")
+               "-style" style
+               "-offset" (number-to-string (1- start))
+               "-length" (number-to-string (- end start))
+               "-cursor" (number-to-string (1- (point))))
+              stderr
+              (with-temp-buffer
+                (insert-file-contents temp-file)
+                (when (> (point-max) (point-min))
+                  (insert ": "))
+                (buffer-substring-no-properties
+                 (point-min) (line-end-position))))
+      (delete-file temp-file))
+
+    (cond
+     ((stringp status)
+      (error "(clang-format killed by signal %s%s)" status stderr))
+     ((not (equal 0 status))
+      (error "(clang-format failed with code %d%s)" status stderr))
+     (t (message "(clang-format succeeded%s)" stderr)))
+
+    (goto-char (point-min))
+    (setq json (json-read-from-string
+                (buffer-substring-no-properties
+                 (point-min) (line-end-position))))
+
+    (delete-region (point-min) (line-beginning-position 2))
+    (mapc (lambda (w) (apply #'set-window-start w))
+          window-starts)
+    (goto-char (1+ (cdr (assoc 'Cursor json))))))
+
+;;;###autoload
+(defun clang-format-buffer (&optional style)
+  "Use clang-format to format the current buffer according to STYLE."
+  (interactive)
+  (clang-format-region (point-min) (point-max) style))
+
+;;;###autoload
+(defalias 'clang-format 'clang-format-region)
+
 (provide 'clang-format)
+;;; clang-format.el ends here
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to