[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
Sun Nov 17 19:16:48 PST 2024


================
@@ -146,18 +146,124 @@ 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))))
+(defmacro clang-format--with-delete-files-guard (bind-files-to-delete &rest body)
+  "Execute BODY which may add temp files to BIND-FILES-TO-DELETE."
+  (declare (indent 1))
+  `(let ((,bind-files-to-delete nil))
+     (unwind-protect
+         (progn
+           , at body)
+       (while ,bind-files-to-delete
+         (with-demoted-errors "failed to remove file: %S"
+           (delete-file (pop ,bind-files-to-delete)))))))
+
+
+(defun clang-format--vc-diff-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’."
+  ;; Use temporary buffer for output of diff.
+  (with-temp-buffer
+    ;; We could use diff.el:diff-no-select here. The reason we don't
+    ;; is diff-no-select requires extra copies on the buffers which
+    ;; induces noticeable slowdowns, especially on larger files.
+    (let ((status (call-process
+                   diff-command
+                   nil
+                   (current-buffer)
+                   nil
+                   ;; Binary diff has different behaviors that we
+                   ;; aren't interested in.
+                   "-a"
+                   ;; Get minimal diff (copy diff config for git-clang-format).
+                   "-U0"
+                   file-orig
+                   file-new))
+          (stderr (concat (if (zerop (buffer-size)) "" ": ")
+                          (buffer-substring-no-properties
+                           (point-min) (line-end-position))))
+          (diff-lines '()))
+      (cond
+       ((stringp status)
+        (error "(diff killed by signal %s%s)" status stderr))
+       ;; Return of 0 indicates no diff.
+       ((= status 0) nil)
+       ;; Return of 1 indicates found diffs and no error.
+       ((= status 1)
+        ;; Find and collect all diff lines.
+        ;; We are matching something like:
+        ;; "@@ -80 +80 @@" or "@@ -80,2 +80,2 @@"
+        (goto-char (point-min))
+        (while (re-search-forward
+                "^@@\s-[0-9,]+\s\\+\\([0-9]+\\)\\(,\\([0-9]+\\)\\)?\s@@$"
+                nil
+                t
+                1)
+          (let ((match1 (string-to-number (match-string 1)))
+                (match3 (if (match-string 3)
----------------
ideasman42 wrote:

`\s-` uses the syntax-table, in this case I think it's reasonable to be more explicit (space-or-tab)

This is a similar regex I used for the package `diff-at-point`.

Not saying you \*should\* use this, but in general I find `[:blank:]` preferable when `a space or tab character` is appropriate, see: https://www.emacswiki.org/emacs/RegularExpression
``
(concat
                                          "^\\(@@\\)[[:blank:]]+"
                                          ;; Previous (ignore).
                                          "-"
                                          "\\([[:digit:]]+\\),\\([[:digit:]]+\\)"
                                          "[[:blank:]]+"
                                          ;; Current (use).
                                          "\\+"
                                          "\\([[:digit:]]+\\),\\([[:digit:]]+\\)"
                                          "[[:blank:]]+@@")
```

https://github.com/llvm/llvm-project/pull/112792


More information about the cfe-commits mailing list