2

summary

If one captures diff output to a file name=*.diff and opens that file in a buffer, one gets nicely-formatted mode=Diff. How to get that directly, without first capturing to a file?

details

I use diff a lot, not only via ediff-buffers (which I love) but also for more obscure purposes, like diffing outputs of processes. I've also been using Emacs for several decades, but continue to learn new aspects and uses. So I was not so much surprised as curious to find that, when I did (from the dir/folder of a local git repo)

$ git diff master origin/master > /tmp/foo__local_vs_remote.diff

and opened the file in a buffer, it displayed in a nicely/usefully colorized (à la ediff) mode=Diff. I had just never before simultaneously

  1. captured diff output to a file
  2. named the file *.diff
  3. opened the file in Emacs

But now I'm trying to capture diff output directly to a buffer and get output like that of the happy mode=Diff, and am failing.

seeking genericity

Note also that, since I use diff in lots of contexts, I'm looking for a solution to the general problem, and not, e.g., just to the git diff problem (which I suspect Magit etc have solved). Seeking genericity, I'll test 3 usecases: "normal" file-vs-file diff, git diff, and process-substitution diff.

platform

$ lsb_release -ds
LMDE 2 Betsy
$ cat /etc/debian_version
8.3
$ uname -rv
3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u4 (2016-02-29)
$ emacs --version
GNU Emacs 24.4.1

options

shell-command

If I do the following (possibly after navigating to a buffer with an appropriate working directory)

  1. M-! <diff command/>
  2. C-x b *Shell Command Output* (where the output of M-!==M-x shell-command goes by default)
  3. M-x diff-mode

... I get the nicely-formatted output. Furthermore

  • this works for all 3 testcases
  • if one runs M-! with another diff command, the new output just overwrites the old, but the buffer maintains diff-mode without user intervention
  • no keybinding changes (as with term-mode)

Chosen answer.

shell-mode

If I either

  1. M-x shell, goto the correct dir/folder, and run git diff master origin/master
  2. am in a buffer on the correct dir/folder, and run M-& git diff master origin/master

I get the dreaded WARNING: terminal is not fully functional.

term-mode

As Emacs User points out, M-x term performs better for this usecase than M-x shell: if I M-x term, goto the correct dir/folder, and run git diff master origin/master, I get nicely colorized output. It's not exactly mode=Diff, but it does the job. Unfortunately

  • That only works for git diff: I get no colorization for either process-substitution or file diff.
  • I find the term-mode keybinding changes highly annoying.
  • I also found term-mode navigation odd: when editing history, my cursor would sometimes bounce around oddly. solved).
TomRoche
  • 592
  • 3
  • 20

2 Answers2

3

You can always write a function to do all the repeated steps for you. This should get you started:

(defun diff-generic(command)
  (interactive "sDiff command:")
  (let ((buffer (generate-new-buffer "*diff-generic*")))
    (with-current-buffer buffer (diff-mode))
    (call-process-shell-command command nil buffer 0)
    (switch-to-buffer buffer)))

In general you can do M-x diff to get that diff output for two arbitrary files. More info on that here: (info "(emacs) Diff Mode")

Magit does provide diff functionality, but take note that it uses it's own mode called magit-diff-mode, that is different from generic emacs diff-mode.

Also emacs bundled package VC provides diff functionality for version control diffs. Unlike magit it works with backends other than git and uses diff-mode, also you can use ediff. Relevant manual: (info "(emacs) Old Revisions")

sg2002
  • 131
  • 3
2

Try

  1. M-! <your diff command/>
  2. C-x b *Shell Command Output* (where the output of M-!==M-x shell-command goes by default)
  3. M-x diff-mode
TomRoche
  • 592
  • 3
  • 20
  • see reasons for choosing in question section=shell-command – TomRoche Mar 04 '16 at 23:46
  • Those reading this answer should be aware that the `WARNING: terminal is not fully functional` is not solved by this accepted solution. It may work for this limited diff case, but if one is `seeking genericity` as the OP requested, please use `M-x term` as a complete solution. See the Emacs documentation for reasons. – Emacs User Mar 05 '16 at 03:42