r225777 - Update clang-format.el to use xml output and patch in the returned chunks.

Manuel Klimek klimek at google.com
Tue Jan 13 00:35:35 PST 2015


Author: klimek
Date: Tue Jan 13 02:35:34 2015
New Revision: 225777

URL: http://llvm.org/viewvc/llvm-project?rev=225777&view=rev
Log:
Update clang-format.el to use xml output and patch in the returned chunks.

This leads to better undo behavior and avoids window content jumping
around.

Patch by Johann Klähn.

Modified:
    cfe/trunk/tools/clang-format/clang-format.el

Modified: cfe/trunk/tools/clang-format/clang-format.el
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-format/clang-format.el?rev=225777&r1=225776&r2=225777&view=diff
==============================================================================
--- cfe/trunk/tools/clang-format/clang-format.el (original)
+++ cfe/trunk/tools/clang-format/clang-format.el Tue Jan 13 02:35:34 2015
@@ -1,7 +1,7 @@
 ;;; clang-format.el --- Format code using clang-format
 
 ;; Keywords: tools, c
-;; Package-Requires: ((json "1.3"))
+;; Package-Requires: ((cl-lib "0.3"))
 
 ;;; Commentary:
 
@@ -28,7 +28,8 @@
 
 ;;; Code:
 
-(require 'json)
+(require 'cl-lib)
+(require 'xml)
 
 (defgroup clang-format nil
   "Format code using clang-format."
@@ -55,6 +56,47 @@ of the buffer."
   :safe #'stringp)
 (make-variable-buffer-local 'clang-format-style)
 
+(defun clang-format--extract (xml-node)
+  "Extract replacements and cursor information from XML-NODE."
+  (unless (and (listp xml-node) (eq (xml-node-name xml-node) 'replacements))
+    (error "Expected <replacements> node"))
+  (let ((nodes (xml-node-children xml-node))
+        replacements
+        cursor)
+    (dolist (node nodes)
+      (when (listp node)
+        (let* ((children (xml-node-children node))
+               (text (car children)))
+          (cl-case (xml-node-name node)
+            ('replacement
+             (let* ((offset (xml-get-attribute-or-nil node 'offset))
+                    (length (xml-get-attribute-or-nil node 'length)))
+               (when (or (null offset) (null length))
+                 (error "<replacement> node does not have offset and length attributes"))
+               (when (cdr children)
+                 (error "More than one child node in <replacement> node"))
+
+               (setq offset (1+ (string-to-number offset)))
+               (setq length (string-to-number length))
+               (push (list offset length text) replacements)))
+            ('cursor
+             (setq cursor (1+ (string-to-number text))))))))
+
+    ;; Sort by decreasing offset, length.
+    (setq replacements (sort (delq nil replacements)
+                             (lambda (a b)
+                               (or (> (car a) (car b))
+                                   (and (= (car a) (car b))
+                                        (> (cadr a) (cadr b)))))))
+
+    (cons replacements cursor)))
+
+(defun clang-format--replace (offset length &optional text)
+  (goto-char offset)
+  (delete-char length)
+  (when text
+    (insert text)))
+
 ;;;###autoload
 (defun clang-format-region (start end &optional style)
   "Use clang-format to format the code between START and END according to STYLE.
@@ -68,51 +110,49 @@ is no active region.  If no style is giv
   (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))
-
+  (let ((temp-buffer (generate-new-buffer " *clang-format-temp*"))
+        (temp-file (make-temp-file "clang-format")))
     (unwind-protect
-        (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))))))
+        (let (status stderr operations)
+          (setq status
+                (call-process-region
+                 (point-min) (point-max) clang-format-executable
+                 nil `(,temp-buffer ,temp-file) nil
+
+                 "-output-replacements-xml"
+                 "-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)))))
+          (setq stderr
+                (with-temp-buffer
+                  (insert-file-contents temp-file)
+                  (when (> (point-max) (point-min))
+                    (insert ": "))
+                  (buffer-substring-no-properties
+                   (point-min) (line-end-position))))
+
+          (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)))
+
+          (with-current-buffer temp-buffer
+            (setq operations (clang-format--extract (car (xml-parse-region)))))
+
+          (let ((replacements (car operations))
+                (cursor (cdr operations)))
+            (save-excursion
+              (mapc (lambda (rpl)
+                      (apply #'clang-format--replace rpl))
+                    replacements))
+            (when cursor
+              (goto-char cursor))))
+      (delete-file temp-file)
+      (when (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
 
 ;;;###autoload
 (defun clang-format-buffer (&optional style)






More information about the cfe-commits mailing list