In org-mode, strike M-}
which invoke org-forward-element
is very handy to jump around.
However, the matching line always stay at the bottom. So I have to manually execute (recenter).
How could add the action (recenter) to org-forward-element
?
I tried a decorator solution, but does not work.
(defun add-recenter(func)
(lambda ()
(func)
(recenter)))
(setq org-element-forward (add-recenter org-element-forward))
This seems to work:
(advice-add 'org-forward-element :after (lambda () (recenter)))
I first tried (advice-add 'org-forward-element :after 'recenter)
, but that didn't work, because if the advice function being added (in this case recenter
) is interactive, its interactive
spec overrides that of the old function (org-forward-element
), which causes an error since recenter
generates one argument while org-forward-element
takes zero arguments.
The reason your code doesn't work is that in Emacs Lisp variables and functions are in separate namespaces, just like Common Lisp and unlike Scheme. This is sometimes described as "Lisp-2", as opposed to "Lisp-1". See e.g. this article: http://ergoemacs.org/emacs/lisp1_vs_lisp2.html
Basically every symbol has both a "value cell" and a "function cell". setq
changes the symbol's value cell, and calling a symbol, like (foo)
, accesses its function cell. The corresponding Emacs Lisp code would be something like:
(defun add-recenter(func)
(lambda ()
(funcall func)
(recenter)))
(fset 'org-element-forward (add-recenter (symbol-function 'org-element-forward)))
That is essentially what the advice-add
call above does.