When using elisp function in the link in org-mode, like


after clicking the link, the function itself will be printed in *Message* buffer. How should I prevent it from being printed? I've tried

(let ((inhibit-output t))

but it doesn't work.


[Editorial comment: I'm not convinced this is a good idea - what difference does it make if the *Messages* buffer has an extra line in it? Despite my misgivings, I provide an answer below.]

The relevant function is org-link--open-elisp. If you check its implementation, you will see that it uses message to print the result of the evaluation to the echo area. But message also copies whatever it prints to the echo area, to the *Messages* buffer. A quick perusal of the doc string for message shows that you can avoid copying to the *Messages* buffer if you set message-log-max to nil. Unfortunately, that is going to turn off all output to the Messages buffer which is a bad thing.

One way to accomplish what you want is to patch the org-link--open-elisp function to bind message-log-max to nil temporarily (as Marco Wahl suggests in his answer), but my suggestion would be to write a new function for this, which is an exact copy of org-link--open-elisp except that it binds message-log-max to nil before calling message:

(defun org-link--open-elisp-silent (path)
  "Open a \"elisp-silent\" type link.
PATH is the sexp to evaluate, as a string."
  (if (or (and (org-string-nw-p org-link-elisp-skip-confirm-regexp)
           (string-match-p org-link-elisp-skip-confirm-regexp path))
      (not org-link-elisp-confirm-function)
      (funcall org-link-elisp-confirm-function
           (format "Execute %S as Elisp? "
               (org-add-props path nil 'face 'org-warning))))
      (let ((message-log-max nil))
         (message "%s => %s" path
           (if (eq ?\( (string-to-char path))
           (eval (read path))
         (call-interactively (read path)))))
    (user-error "Abort")))

You can then add a new link type "elisp-silent" that is handled by this function:

(org-link-set-parameters "elisp-silent" :follow #'org-link--open-elisp-silent)

Now [[elisp:(func)][verbose]] works as before and [[elisp-silent:(func)][silent]] works the same way but avoids writing to the *Messages* buffer.

This technique of binding a variable around a function call is general and well-worth understanding if you are going to be doing elisp programming.

  • I like the idea of introducing a new protocol for that purpose. – Tobias Mar 6 '20 at 0:26
  • What is wrong on (defun org-link--open-elisp-silent (path) (let (message-log-max) (org-link--open-elisp path)))? – Tobias Mar 6 '20 at 0:33
  • Nothing (as I know you know :-)): I was just being stupid. – NickD Mar 6 '20 at 3:17

Since the message comes from the respective org mode function you need to somehow circumvent that function. You could patch that function.

Actually I think it's a good idea to see the message since this gives transparency to the evaluation. Note that the code evaluation could bring irritation and even harm.


A shorter way to accomplish this is with advice (https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html). Here you can use :around advice to let-bind the variable and then call the original function with its arguments.

(defun silence (orig-func &rest args)
  (let ((message-log-max nil))
    (apply orig-func args)))

(advice-add 'org-link--open-elisp :around 'silence)

Later you can remove the advice like this:

(advice-remove 'org-link--open-elisp 'silence)

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.