@tmalsburg, Following command calls diff on 2 buffers without the creation
of temporary files. It uses named pipes as you suggested above:
(require 'diff)
(defun diff-buffers-without-temp-files (buffer1 buffer2 &optional switches)
"Run diff program on BUFFER1 and BUFFER2.
Make the comparison without the creation of temporary files.
When called interactively with a prefix argument, prompt
interactively for diff switches. Otherwise, the switches
specified in the variable `diff-switches' are passed to the diff command."
(interactive
(list (read-buffer "buffer1: " (current-buffer))
(read-buffer "buffer2: " (current-buffer))
(diff-switches)))
(or switches (setq switches diff-switches))
(unless (listp switches) (setq switches (list switches)))
(let ((buffers (list buffer1 buffer2))
(buf (get-buffer-create "*diff-buffers*"))
fifos res)
(dotimes (_ 2) (push (make-temp-name "/tmp/pipe") fifos))
(setq fifos (nreverse fifos))
(with-current-buffer buf (erase-buffer))
(unwind-protect
(progn
(dotimes (i 2)
(let ((cmd (format "cat > %s << EOF\n%s\nEOF"
(nth i fifos)
(with-current-buffer (nth i buffers)
(buffer-string)))))
(call-process "mkfifo" nil nil nil (nth i fifos))
(start-process-shell-command (format "p%d" i) nil cmd)))
(setq res (apply #'call-process diff-command nil buf nil (car fifos) (cadr fifos) switches))
(if (zerop res)
(message "Buffers have same content")
(display-buffer buf)
(with-current-buffer buf (diff-mode))
(message "Buffer contents are different"))
res)
;; Clean up.
(dolist (x fifos)
(and (file-exists-p x) (delete-file x))))))
- When called interactively, it shows the diff when the buffers have different content.
- When called from Lisp, it returns the exit code of the diff program; that is, 0 if the
buffers have same content, 1 otherwise.
(diff-buffers-without-temp-files (get-buffer "*scratch*") (get-buffer "*scratch*"))
=> 0
(diff-buffers-without-temp-files (get-buffer "*scratch*") (get-buffer "*Messages*"))
=> 1
Tested for Emacs version 24.3 in a machine running Debian GNU/Linux 9.0 (stretch).
The code above seems to work whed called from Lisp. Unfortunately, most of the time shows a truncated diff in interactive calls.
The following version uses the 3rd party async library; it doesn't truncate the diffs.
(require 'diff)
(require 'async)
(defun diff-buffers-without-temp-files (buffer1 buffer2 &optional switches)
"Run diff program on BUFFER1 and BUFFER2.
Make the comparison without the creation of temporary files.
When called interactively with a prefix argument, prompt
interactively for diff switches. Otherwise, the switches
specified in the variable `diff-switches' are passed to the diff command."
(interactive
(list (read-buffer "buffer1: " (current-buffer))
(read-buffer "buffer2: " (current-buffer))
(diff-switches)))
(or switches (setq switches diff-switches))
(unless (listp switches) (setq switches (list switches)))
(let ((buffers (list buffer1 buffer2))
(buf (get-buffer-create "*diff-buffers*"))
fifos res)
(dotimes (_ 2) (push (make-temp-name "/tmp/pipe") fifos))
(setq fifos (nreverse fifos))
(with-current-buffer buf (erase-buffer))
(unwind-protect
(progn
(dotimes (i 2)
(let ((cmd (format "cat > %s" (nth i fifos))))
(call-process "mkfifo" nil nil nil (nth i fifos))
(async-start
`(lambda ()
(with-temp-buffer
(insert ,(with-current-buffer (nth i buffers) (buffer-string)))
(call-process-region
1 (point-max) shell-file-name nil nil nil
shell-command-switch ,cmd))))))
(setq res (apply #'call-process diff-command nil buf nil (car fifos) (cadr fifos) switches))
(if (zerop res)
(message "Buffers have same content")
(display-buffer buf)
(with-current-buffer buf (diff-mode))
(message "Buffer contents are different"))
res)
;; Clean up.
(dolist (x fifos)
(and (file-exists-p x) (delete-file x))))))
ediff-buffers
very briefly, it appears to save buffers to temporary files on disk, then call the system diff utility on those files, so there wouldn't be any practical difference from callingdiff
yourself. – user2699 Sep 27 '16 at 11:46http://stackoverflow.com/a/345536/3255378
– JCC Sep 27 '16 at 12:23