21

If I have a code snippet that I tangle to a file, but I expect the file name to change over time, Is there a cleaner way to change the filename than Query-replace?

For example, say I tangle code to ~/dir/my-file.el:

#+BEGIN_SRC emacs-lisp :tangle ~/dir/my-file.el
(setq myvar1 "value1")
#+END_SRC

#+BEGIN_SRC emacs-lisp :tangle ~/dir/my-file.el
(defun foo (bar) ... )
#+END_SRC

etc.

Then later on I realize that the file would be better placed in another location:

#+BEGIN_SRC emacs-lisp :tangle ~/dir/my/file.el
(setq myvar1 "value1")
#+END_SRC

#+BEGIN_SRC emacs-lisp :tangle ~/dir/my/file.el
(defun foo (bar) ... )
#+END_SRC

etc.

Is there a way to change the argument to :tangle dynamically.

I have investigated and discovered that I can feed elisp into the :tangle argument. If I evaluate (setq myfile "~/dir/file.el) and then tangle the following:

#+BEGIN_SRC emacs-lisp :tangle (print myfile)
(setq myvar1 "value1")
#+END_SRC

#+BEGIN_SRC emacs-lisp :tangle (print myfile)
(defun foo (bar) ... )
#+END_SRC

I get the desired result I am looking for. I could then execute an elisp snippet to set the variable using org-babel, but I was wondering if there is a cleaner way to do so.

The docs on the :tangle header do not stipulate a native way.

Malabarba
  • 22,878
  • 6
  • 78
  • 163
Gambo
  • 929
  • 5
  • 14

2 Answers2

19

You should not repeat such things, but define them in one place. For example you can define output file in a drawer as header args for whole tree and subtrees:

* Header
:PROPERTIES:
:tangle: ~/dir/my/testfile.el
:END:

or for :dir

* Header
:PROPERTIES:
:header-args: :dir ~/dir/my/dir/
:END:

As described in docs you can have:

  • System-wide header arguments
  • Language-specific header arguments
  • Header arguments in Org mode properties
  • Language-specific header arguments in Org mode properties
  • Code block specific header arguments
  • Header arguments in function calls
mararm
  • 3
  • 4
kmicu
  • 2,395
  • 1
  • 15
  • 15
7

You can use a property of the org heading instead of a setq

* Header
:PROPERTIES:
:PRJ-DIR: ~/prj/dir/
:END:

#+BEGIN_SRC emacs-lisp :tangle (concat (org-entry-get nil "PRJ-DIR" t) "file.el")
(setq myvar1 "value1")
#+END_SRC

#+BEGIN_SRC emacs-lisp :tangle (concat (org-entry-get nil "PRJ-DIR" t) "file.el")
(defun foo (bar) ... )
#+END_SRC

etc.

This way you can set different file names for each source block.