diff options
| author | Craig Jennings <c@cjennings.net> | 2025-11-09 15:31:41 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2025-11-09 15:31:41 -0600 |
| commit | e3fda13930b46820f2cbdf29b33d9ef3c99fea7f (patch) | |
| tree | 4487fce5f6863d2903028549225d8a49ced834cf /modules/custom-buffer-file.el | |
| parent | 8176eff73b826f7fec9d7f458f7d2f36f4d12e58 (diff) | |
feat:buffer-diff: Add syntax-aware buffer diffing with difftastic
Introduce enhanced buffer comparison with saved file using difftastic
for syntax-aware diffing, with a fallback to regular unified diff if
difftastic is unavailable. Output is displayed in separate buffers,
leveraging ansi-color for improved readability. Also includes
comprehensive integration tests covering the diff workflow, handling
cases like added, removed, and modified lines, and ensuring graceful
handling of special cases and errors.
Diffstat (limited to 'modules/custom-buffer-file.el')
| -rw-r--r-- | modules/custom-buffer-file.el | 67 |
1 files changed, 62 insertions, 5 deletions
diff --git a/modules/custom-buffer-file.el b/modules/custom-buffer-file.el index 105ed4ff..8825fdd6 100644 --- a/modules/custom-buffer-file.el +++ b/modules/custom-buffer-file.el @@ -251,14 +251,71 @@ Do not save the deleted text in the kill ring." (kill-new (buffer-name)) (message "Copied: %s" (buffer-name))) +(require 'system-lib) +(declare-function ansi-color-apply-on-region "ansi-color") + +(defun cj/--diff-with-difftastic (file1 file2 buffer) + "Run difftastic on FILE1 and FILE2, output to BUFFER. +Applies ANSI color and sets up special-mode for navigation." + (with-current-buffer buffer + (let ((inhibit-read-only t)) + (erase-buffer) + (insert (format "Difftastic diff: %s (saved) vs buffer (modified)\n\n" + (file-name-nondirectory file1))) + (call-process "difft" nil t nil + "--color" "always" + "--display" "side-by-side-show-both" + file1 file2) + (require 'ansi-color) + (ansi-color-apply-on-region (point-min) (point-max)) + (special-mode) + (goto-char (point-min))))) + +(defun cj/--diff-with-regular-diff (file1 file2 buffer) + "Run regular unified diff on FILE1 and FILE2, output to BUFFER. +Sets up diff-mode for navigation." + (with-current-buffer buffer + (let ((inhibit-read-only t)) + (erase-buffer) + (insert (format "Unified diff: %s (saved) vs buffer (modified)\n\n" + (file-name-nondirectory file1))) + (call-process "diff" nil t nil "-u" file1 file2) + (diff-mode) + (goto-char (point-min))))) + (defun cj/diff-buffer-with-file () - "Compare the current modified buffer with the saved version using ediff. -Uses the same ediff configuration from diff-config.el (horizontal split, j/k navigation). + "Compare the current modified buffer with the saved version. +Uses difftastic if available for syntax-aware diffing, falls back to regular diff. +Shows output in a separate buffer. Signal an error if the buffer is not visiting a file." (interactive) - (if (buffer-file-name) - (ediff-current-file) - (user-error "Current buffer is not visiting a file"))) + (unless (buffer-file-name) + (user-error "Current buffer is not visiting a file")) + (let* ((file (buffer-file-name)) + (file-ext (file-name-extension file t)) ; includes the dot + (temp-file (make-temp-file "buffer-diff-" nil file-ext)) + (buffer-content (buffer-string))) ; Capture BEFORE with-temp-file! + (unwind-protect + (progn + ;; Write current buffer content to temp file + (with-temp-file temp-file + (insert buffer-content)) + ;; Check if there are any differences first + (if (zerop (call-process "diff" nil nil nil "-q" file temp-file)) + (message "No differences between buffer and file") + ;; Run diff/difftastic and display in buffer + (let* ((using-difftastic (cj/executable-exists-p "difft")) + (buffer-name (if using-difftastic + "*Diff (difftastic)*" + "*Diff (unified)*")) + (diff-buffer (get-buffer-create buffer-name))) + (if using-difftastic + (cj/--diff-with-difftastic file temp-file diff-buffer) + (cj/--diff-with-regular-diff file temp-file diff-buffer)) + (display-buffer diff-buffer)))) + ;; Clean up temp file + (when (file-exists-p temp-file) + (delete-file temp-file))))) ;; --------------------------- Buffer And File Keymap -------------------------- |
