11

By default, Org-mode will override current babel src block content on file original content (when the file already has content).

For example, I have an org-mode file content as the bellowing block:

#+BEGIN_SRC org
,* config file

,** config 1

,#+BEGIN_SRC clojure :tangle "data/code/tangle-append-test.clj"
(println "hello")
,#+END_SRC

,** config 2

,#+BEGIN_SRC clojure :tangle "data/code/tangle-append-test.clj"
(println "world")
,#+END_SRC

#+END_SRC

If you tangle the whole buffer file, then the result will looks like this:

The tangled file result content:

#+NAME: data/code/tangle-append-test.clj
#+BEGIN_SRC clojure
(println "hello")

(println "world")

#+END_SRC

This is fine. But here is my problem:

But if you tangle only current src block with [C-u C-c C-v t]. Then the current tangled src block will overwrite the whole destination file, like this:

 $ cat data/code/tangle-append-test.clj

(println "world")

UPDATED

My question: The single babel block override original file content, I hope to only append current tangled block without overwriting.

8
  • I was wondering if you came up with a decent solution since you posted this question. I'd be interested in hearing it out
    – Daniel
    Commented Mar 13, 2017 at 19:51
  • @dangom Maybe use an advice to detect tangle file exist or not, or empty then decide whether overwrite or append. But I don't know how to write this advice. Commented Mar 14, 2017 at 1:41
  • @stardiviner, Why would you want to only tangle the current block? I always use M-x org-babel-tangle (C-c C-v t) and tangle all blocks in the file. My tangled files are in the .gitignore anyway because I treat them only as an artifact to run the application. They are essentially throwaway code, I regenerate them whenever I need to. The real code is in the source blocks.
    – Martín
    Commented Feb 16, 2018 at 23:25
  • I'm not want to only tangle the current block. I want to append block to file instead of override. And because I use it in Literate DevOps style with Org-mode. Commented Feb 17, 2018 at 2:05
  • What I mean is, in Literate Programming the idea is that the source code is in the document, and you process the document to generate the source files or scripts needed to run your application. What harm does it do to regenerate all tangled files from scratch? Why do you need to only tangle the current block and append it to the file? What benefit does that have that is better than regenerating all the files?
    – Martín
    Commented Feb 18, 2018 at 16:16

3 Answers 3

7
+100

The following elisp code defines a new function org-babel-tangle-append appending the current source block to the tangle file. In org-mode 9.1.6 there is no user option to configure org-babel-tangle in that way.

If you copy-paste the full elisp code into your init file behind package-initialize the new function org-babel-tangle-append is bound to the key sequence C-c C-v + in org-mode after the next restart of emacs.

The code is tested with

  • emacs-version 25.1.50.2
  • org-version 9.1.6

In org-babel-tangle of that org version the old tangle file is deleted with delete-file before the new block(s) are collected there. The new function org-babel-tangle-append works by calling org-babel-tangle with delete-file temporarily overridden by ignore.

(defun org-babel-tangle-append ()
  "Append source code block at point to its tangle file.
The command works like `org-babel-tangle' with prefix arg
but `delete-file' is ignored."
  (interactive)
  (cl-letf (((symbol-function 'delete-file) #'ignore))
    (org-babel-tangle '(4))))

(defun org-babel-tangle-append-setup ()
  "Add key-binding C-c C-v C-t for `org-babel-tangle-append'."
  (org-defkey org-mode-map (kbd "C-c C-v +") 'org-babel-tangle-append))

(add-hook 'org-mode-hook #'org-babel-tangle-append-setup)
7
  • Is it possible to an advice with advice-add? Commented Feb 19, 2018 at 6:07
  • @stardiviner It is clearly possible to advice org-babel-tangle. But why would you do that? Appending the source blocks is added functionality and not something like a bugfix. So a new command is better than modifying the old one IMHO.
    – Tobias
    Commented Feb 19, 2018 at 7:27
  • This is not answer in my case... I need to update file, not rewrite it, because of old bug in node fs watcher, that broke livereloading in many node applications Commented Apr 8, 2018 at 13:36
  • 1
    @William The use of 4 in (org-babel-tangle '(4)) is how C-u is effected in code. See How is "C-u" expressed in function call? : emacs
    – vfclists
    Commented Aug 25, 2020 at 21:56
  • 1
    @vfclists cl-letf is well-documented at gnu.org/software/emacs/manual/html_node/cl/Modify-Macros.html. In that context (symbol-function SYMBOL) is one of the posible places. that specifies the function cell of SYMBOL. Yes, the binding of delete-file to #'ignore is local to the body of the cl-letf.
    – Tobias
    Commented Dec 27, 2020 at 5:23
11

I recommend using the builtin org-mode :noweb-ref header to concatenate the code blocks because doing so will resolve the block tangling issue and will allow more flexibility in the future.

  • Updated Code

      * config file
    
      #+BEGIN_SRC clojure :noweb yes :exports none :mkdirp yes :tangle data/code/tangle-append-test.clj 
        <<configs>>
      #+END_SRC
    
      ** config 1
    
      #+BEGIN_SRC clojure :noweb-ref configs
        (println "hello")
      #+END_SRC
    
      ** config 2
    
      #+BEGIN_SRC clojure :noweb-ref configs
        (println "world")
      #+END_SRC
    
  • Tangling the code with C-c C-v C-t produces:

      (println "hello")
      (println "world")
    

As new sections are added, deleted, moved, or updated, tangling the code should always produce the code in the order expected:

  • Future Code

      * config file
    
      #+BEGIN_SRC clojure :noweb yes :exports none :mkdirp yes :tangle data/code/tangle-append-test.clj 
        <<configs>>
      #+END_SRC
    
      ** config 1 - Added
    
      #+BEGIN_SRC clojure :noweb-ref configs
        (println "Howdy")
      #+END_SRC
    
      ** config 2 - Updated
    
      #+BEGIN_SRC clojure :noweb-ref configs
        (println "World")
      #+END_SRC
    
      ** config 1 - Moved
    
      #+BEGIN_SRC clojure :noweb-ref configs
        (println "hello")
      #+END_SRC
    
      ** config 4 - Added 
    
      #+BEGIN_SRC clojure :noweb-ref configs
        (println "earth")
      #+END_SRC
    
  • Future Tangle

      (println "Howdy")
      (println "World")
      (println "hello")
      (println "earth")
    

Hope that helped.


This code was tested using:
GNU Emacs 25.2.1 (x86_64-unknown-cygwin, GTK+ Version 3.22.10)
Org mode version 9.1.2

1
  • 2
    Excellent! Thank-you for an elegant and self-contained answer ^_^ Commented Oct 1, 2019 at 17:22
3

What I do is I specify a single block per output file, and use noweb references to collect what goes into it:

Here are the blocks with the source you want:

#+name: hello-world
#+begin_src clojure
(println "hello")
#+end_src

#+name: hello-world
#+begin_src clojure
(println "world")
#+end_src

#+name: goodbye
#+begin_src clojure
(println "goodbye")
#+end_src

Here's the block that collects it all and tangles it:

#+begin_src clojure :noweb yes :tangle data/code/tangle-append-test.clj
<<hello-world>>
<<goodbye>>
#+end_src
1
  • I updated my question, check it out. your answer is not what I want. Commented Oct 25, 2016 at 9:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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