4

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.

  • I was wondering if you came up with a decent solution since you posted this question. I'd be interested in hearing it out – dangom Mar 13 '17 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. – stardiviner Mar 14 '17 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 Feb 16 '18 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. – stardiviner Feb 17 '18 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 Feb 18 '18 at 16:16
1
+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)
  • Is it possible to an advice with advice-add? – stardiviner Feb 19 '18 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 Feb 19 '18 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 – 11111000000 Apr 8 '18 at 13:36
2

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
  • I updated my question, check it out. your answer is not what I want. – stardiviner Oct 25 '16 at 9:45
2

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

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.