[clang] [emacs][clang-format] Add elisp API for clang-format on git diffs (PR #112792)
Campbell Barton via cfe-commits
cfe-commits at lists.llvm.org
Sat Nov 2 20:46:46 PDT 2024
================
@@ -132,18 +132,97 @@ is a zero-based file offset, assuming ‘utf-8-unix’ coding."
(lambda (byte &optional _quality _coding-system)
(byte-to-position (1+ byte)))))
-;;;###autoload
-(defun clang-format-region (start end &optional style assume-file-name)
- "Use clang-format to format the code between START and END according to STYLE.
-If called interactively uses the region or the current statement if there is no
-no active region. If no STYLE is given uses `clang-format-style'. Use
-ASSUME-FILE-NAME to locate a style config file, if no ASSUME-FILE-NAME is given
-uses the function `buffer-file-name'."
- (interactive
- (if (use-region-p)
- (list (region-beginning) (region-end))
- (list (point) (point))))
+(defun clang-format--git-diffs-get-diff-lines (file-orig file-new)
+ "Return all line regions that contain diffs between FILE-ORIG and
+FILE-NEW. If there is no diff 'nil' is returned. Otherwise the
+return is a 'list' of lines in the format '--lines=<start>:<end>'
+which can be passed directly to 'clang-format'"
+ ;; Temporary buffer for output of diff.
+ (with-temp-buffer
+ (let ((status (call-process
+ "diff"
+ nil
+ (current-buffer)
+ nil
+ ;; Binary diff has different behaviors that we
+ ;; aren't interested in.
+ "-a"
+ ;; Printout changes as only the line groups.
+ "--changed-group-format=--lines=%dF:%dL "
+ ;; Ignore unchanged content.
+ "--unchanged-group-format="
+ file-orig
+ file-new
+ )
+ )
+ (stderr (concat (if (zerop (buffer-size)) "" ": ")
+ (buffer-substring-no-properties
+ (point-min) (line-end-position)))))
+ (when (stringp status)
+ (error "(diff killed by signal %s%s)" status stderr))
+ (unless (= status 0)
+ (unless (= status 1)
+ (error "(diff returned unsuccessfully %s%s)" status stderr)))
+
+
+ (if (= status 0)
+ ;; Status == 0 -> no Diff.
+ nil
+ (progn
+ ;; Split "--lines=<S0>:<E0>... --lines=<SN>:<SN>" output to
+ ;; a list for return.
+ (s-split
+ " "
+ (string-trim
+ (buffer-substring-no-properties
+ (point-min) (point-max)))))))))
+
+(defun clang-format--git-diffs-get-git-head-file ()
+ "Returns a temporary file with the content of 'buffer-file-name' at
+git revision HEAD. If the current buffer is either not a file or not
+in a git repo, this results in an error"
+ ;; Needs current buffer to be a file
+ (unless (buffer-file-name)
+ (error "Buffer is not visiting a file"))
+ ;; Need to be able to find version control (git) root
+ (unless (vc-root-dir)
+ (error "File not known to git"))
+ ;; Need version control to in fact be git
+ (unless (string-equal (vc-backend (buffer-file-name)) "Git")
+ (error "Not using git"))
+
+ (let ((tmpfile-git-head (make-temp-file "clang-format-tmp-git-head-content")))
----------------
ideasman42 wrote:
>From what I can tell this temporary file is never deleted, further, any errors after creating the temporary file would leave it created.
Without attempting to do this myself, I'm not sure of the best solution but suggest: `(with-temp-file ...)`
The caller would need to use this and pass in the temporary file file. If the behavior of `with-temp-file` isn't what your after, you could write your own macro that creates a scoped temporary file that gets removed in case of errors.
https://github.com/llvm/llvm-project/pull/112792
More information about the cfe-commits
mailing list