0

I'm writing a programming tutorial. In between the prose I have diff code blocks that show exactly what changes are done to the code on each step. To make sure the diffs are correct I'd like to be able to evaluate them using patch command. Here is an example:

* Setup tests

Bla bla bla...

#+begin_src diff
--- a/elm.json
+++ b/elm.json
@@ -18,7 +18,11 @@
         }
     },
     "test-dependencies": {
-        "direct": {},
-        "indirect": {}
+        "direct": {
+            "elm-explorations/test": "1.2.2"
+        },
+        "indirect": {
+            "elm/random": "1.0.0"
+        }
     }
 }

Is it possible to do this from Emacs? When I try to evaluate this code block (pressing Enter inside it) I get:

No org-babel-execute function for diff!

I'm using Doom Emacs on Linux.

3

You can make your own execute function for diff blocks.

#+BEGIN_SRC emacs-lisp
(defun org-babel-execute:diff (body params)
  (with-temp-buffer
    (insert body "\n")
    (shell-command-on-region (point-min) (point-max) "patch" "*patch*")
    (prog1
    (with-current-buffer "*patch*" (buffer-string))
      (kill-buffer "*patch*"))))
#+END_SRC

#+RESULTS: : org-babel-execute:diff

Here are two files that we should tangle, they differ only slightly in the second line.

#+BEGIN_SRC org :tangle a.org
1
2
#+END_SRC

#+BEGIN_SRC org :tangle b.org
1
3
#+END_SRC

Now, run this block to generate the two files, and create the diff block. After that, you can "run" the diff block by typing C-c C-c in it, which will apply the patch to a.org.

#+BEGIN_SRC sh :results raw :var diff=(org-babel-tangle)  :wrap src diff
exec 2>&1
diff -u a.org b.org
:
#+END_SRC


#+RESULTS:
#+begin_src diff
--- a.org   2021-02-21 20:20:27.000000000 -0500
+++ b.org   2021-02-21 20:20:27.000000000 -0500
@@ -1,2 +1,2 @@
 1
-2
+3
#+end_src

#+RESULTS:
: patching file a.org

#+BEGIN_SRC sh
cat a.org
#+END_SRC

#+RESULTS:
| 1 |
| 3 |

This is only tested on this example, but I guess should work for others.

1
  • 1
    Works perfectly. Thank you! It's not really Babel specific, but to make the patch work in subdirectories and ignore only the a/ and b/ prefixes generated by git, I've added --strip=1 option to the command. – Tad Lispy Feb 23 at 9:16
1

Another implementation, possibly shorter. Does not require elisp.

#+NAME: diff
#+BEGIN_SRC bash :var a="foo.txt" b="bar.txt" :results verbatim :wrap src diff
diff -u $a $b
patch -s $a <(diff -u $a $b)
#+END_SRC
#+CALL: diff(a="foo.txt", b="bar.txt")
#+RESULTS:
#+begin_src diff
--- foo.txt 2021-02-22 04:58:22.638960760 -0800
+++ bar.txt 2021-02-22 04:58:29.434904292 -0800
@@ -1,2 +1,2 @@
-hello
+goodbye
 world
#+end_src
2
  • 1
    That generates the diff block, but it does not provide for the evaluation of the diff block (the patching of the file). – NickD Feb 22 at 14:11
  • Edited to apply patch. – mankoff Feb 22 at 15:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.