@tmalsburg, O comando a seguir chama diff em 2 buffers sem a criação de arquivos temporários. Ele usa pipes nomeados, como sugerido acima:
(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))))))
- Quando chamado de forma interativa, mostra o diff quando os buffers têm conteúdo diferente.
Quando chamado do Lisp, retorna o código de saída do programa diff; ou seja, 0 se os buffers tiverem o mesmo conteúdo, 1 caso contrário.
(diff-buffers-without-temp-files (get-buffer "*scratch*") (get-buffer "*scratch*"))
=> 0
(diff-buffers-without-temp-files (get-buffer "*scratch*") (get-buffer "*Messages*"))
=> 1
Testado para o Emacs versão 24.3 em uma máquina executando o Debian GNU / Linux 9.0 (stretch).
O código acima parece funcionar quando chamado de Lisp. Infelizmente, na maioria das vezes mostra uma diferença truncada nas chamadas interativas.
A versão a seguir usa a biblioteca assíncrona de terceiros ; não trunca as diferenças.
(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))))))