21

I have elisp code I'd like to run in orgmode files when they load (different for different files, and defined in the file itself). Is there a way to do this? I didn't see anything in http://orgmode.org/manual/In_002dbuffer-settings.html

If I can add something to emacs initialization that runs a specially named code block whenever an orgmode file loads, that might be a solution, but I'm not sure how to do that, and ideally there is something built in.

6
  • 1
    File-local variables, perhaps?
    – Dan
    Jun 6, 2015 at 7:01
  • That works! Do you want to make it into an answer that I can accept?
    – avv
    Jun 6, 2015 at 8:01
  • On further thought that is a very messy environment to edit in, so a good solution would have the file local variable running a named code block.
    – avv
    Jun 6, 2015 at 8:29
  • Wrap it in a progn or a lambda, perhaps?
    – Dan
    Jun 6, 2015 at 12:38
  • 6
    You can also use # -*- eval: (lisp code here) -*- but you also have to be aware of the dangers. Even if you don't share these documents with anyone else, the interpreted nature of Emacs Lisp will mean that a change may accidentally result in loss of data. Also, mode hook sounds like a better option if you want to run the same code for more than one file.
    – wvxvw
    Jun 6, 2015 at 13:51

5 Answers 5

20

This solution requires no change in init.el (with minor modifications). It involves file-local evaluations, though - but that's exactly what the OP asked for. Advantages of the solution are:

  • asks for confirmation to evaluate code
  • elisp code can be edited and tested within the org-babel environment
  • as the solution doesn't require modifications to init.el the orgmode file may be shared among (trusted) users

I'm rephrasing the solution here.

Add a src-block somewhere in your file:

#+NAME: startup
#+BEGIN_SRC emacs-lisp
(your-code-here)
#+END_SRC

Then, put this at the end of your orgmode-file:

# Local Variables:
# eval: (progn (org-babel-goto-named-src-block "startup") (org-babel-execute-src-block) (outline-hide-sublevels 1))
# End:

I've added (outline-hide-sublevels 1) because I like to hide the src-block inside a heading and want the sublevels to be hidden on startup. Without this statement, the sublevels will become expanded by (org-babel-goto-named-src-block "startup").

With this solution, emacs will ask 2 times for permission to execute (1st: apply Local Variables; 2nd: execute "startup"-src-block). As I have a lot of src-blocks in my file, I've set another file-local-variable, org-confirm-babel-evaluate, like this:

# Local Variables:
# org-confirm-babel-evaluate: nil
# eval: (progn (org-babel-goto-named-src-block "startup") (org-babel-execute-src-block) (outline-hide-sublevels 1))
# End:

Warning: With this addition, emacs will prompt only once for permission to execute - all src-blocks in that file may now be executed without further confirmation. As others have pointed out before, this behavior could be dangerous and you should be very careful with this setting.

However, I'd argue that this solution (especially the first version) is more secure than the one given by Joe Corneli because at least you will be asked for confirmation to execute. Joe's solution will evaluate the special block without confirmation, if it is found in the file. An attacker would have to guess the name of the special block, of course...

I'm using this approach to write large documents which require, e.g., adaptions to the org-export mechanisms.

5

org-mode ... In addition to any hooks its parent mode outline-mode might have run, this mode runs the hook org-mode-hook, as the final step during initialization.

So, in your init.el:

(defun function-that-finds-and-evaluates-special-block ()
;; DWIM :-)
)
(add-hook 'org-mode-hook 'function-that-finds-and-evaluates-special-block)
3
  • This sounds more reasonable to me than file-local vars, for this task. But perhaps I'm missing something.
    – Drew
    Jun 7, 2015 at 2:24
  • @Joe Corneli And then what would you put in the actual org file? Jul 23, 2015 at 22:56
  • Nothing special except for the "special block". Jul 24, 2015 at 23:24
4

Since you ask for

(different for different files, and defined in the file itself)

then, try this solution.

2
  • Care to explain why the down vote?
    – Emacs User
    Jul 23, 2015 at 23:27
  • It's because answers that are just links to other answers are discouraged. That being said, maybe this question is a dupe of the one you linked to? Jan 9, 2020 at 15:18
3

I have tried to improve the code from Joe Corneli:

You need that in your init.el file:

  (defun tdh/eval-startblock ()
    (if (member "startblock" (org-babel-src-block-names))
      (save-excursion
        (org-babel-goto-named-src-block "startblock")
        (org-babel-execute-src-block))
      nil
      )
    )
  (add-hook 'org-mode-hook 'tdh/eval-startblock)

Each time you open an org-mode buffer, it will search for a source block named startblock, if one is found, it will execute it.

In you org-mode files, you can then put:

#+NAME: startblock
#+BEGIN_SRC emacs-lisp
  ;; Any code you want
#+END_SRC
1

I agree with @Joe Corneli's suggestion about using a hook.

It occurs to me too that you could leverage bookmarks here: put a specific bookmark jump on the hook. An advantage of a bookmark to the code block is that it typically gets relocated automatically (e.g. as the file content changes), so locating the block should typically be automatically taken care of.

[But it's not clear to me why you have the code in the Org-mode files, instead of elsewhere. We're taking that as a given, per the problem statement, but I wonder why you are doing that. Letting us know more about the design in that respect might lead to better help.]

Your Answer

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

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