forked from OSchip/llvm-project
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. llvm-svn: 225777
This commit is contained in:
parent
d5946f51a5
commit
1ba46c661c
|
@ -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 given uses `clang-format-style'."
|
|||
(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
|
||||
(let (status stderr operations)
|
||||
(setq status
|
||||
(call-process-region
|
||||
(point-min) (point-max) clang-format-executable
|
||||
nil `(,temp-buffer ,temp-file) 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))
|
||||
"-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)))
|
||||
(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))))
|
||||
(with-current-buffer temp-buffer
|
||||
(setq operations (clang-format--extract (car (xml-parse-region)))))
|
||||
|
||||
(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 ((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)
|
||||
|
|
Loading…
Reference in New Issue