3

I am trying to implement the auto-indentation snippet posted by @Malabarba in one of the emacs SE questions.

From that post, below is the function that I am trying to add to the post-command-hook:

(require 'cl-lib)
(defun endless/indent-defun ()
  "Indent current defun.
Do nothing if mark is active (to avoid deactivaing it), or if
buffer is not modified (to avoid creating accidental
modifications)."
  (interactive)
  (unless (or (region-active-p)
              buffer-read-only
              (null (buffer-modified-p)))
    (let ((l (save-excursion (beginning-of-defun 1) (point)))
          (r (save-excursion (end-of-defun 1) (point))))
      (cl-letf (((symbol-function 'message) #'ignore))
        (indent-region l r)))))

But emacs is removing it from that hook as it seems to be causing some error.

If I call the function using M-x, it runs fine and doesn't throw any error; it just doesn't run when executed via the post-command-hook.

Question: How can I find what's causing the removal of that function from the hook?

I am using the following code to add that function to the hook only for elisp mode:

(defun endless/activate-aggressive-indent ()
   "Locally add `endless/indent-defun' to `post-command-hook'."
   (add-hook 'post-command-hook
             #'endless/indent-defun nil 'local))

 (add-hook 'emacs-lisp-mode-hook
           #'endless/activate-aggressive-indent)
Drew
  • 75,699
  • 9
  • 109
  • 225
Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
  • 1
    What's the code that you're using to add it to `post-command-hook`? After you run that code and you inspect the contents of `post-command-hook`, is the command listed? – Dan Oct 10 '14 at 14:41
  • @Dan I have updated the question will full code. – Kaushal Modi Oct 10 '14 at 14:43
  • If you had visited the answer you linked to, you might have noticed I updated it with `ignore-errors `. :-) – Malabarba Oct 10 '14 at 15:38
  • @Malabarba Ah! How did I miss that; this was reinvention of the wheel. But I learned from that :) I used the code from your blog. – Kaushal Modi Oct 10 '14 at 15:40

3 Answers3

4

Hooks are intentionally removed from post-command-hook because otherwise a bad hook could lead to a condition where it becomes impossible to do anything, including figuring out what is going wrong, because the errors happens when ever the user does anything what-so-ever...

tarsius
  • 25,298
  • 4
  • 69
  • 109
  • 1
    I believe that the question then I need to ask is how to make that function not throw an error. – Kaushal Modi Oct 10 '14 at 15:11
  • `(when (and l r) ....)` – tarsius Oct 10 '14 at 15:12
  • Thanks! I wrapped the function in `(ignore-errors ..)` and that also worked! I tried using `when (and l r) ..)` but that doesn't work as I think that the function errors out by the `(beginning-of-defun ..)` and `(end-of-defun ..)` calls. – Kaushal Modi Oct 10 '14 at 15:15
  • I have removed my speculation on what is causing the error - that was obviously wrong. – tarsius Oct 10 '14 at 15:28
4

Don't just make the function on post-command-hook ignore errors. Instead, you can debug it to find out what the error is, and fix that. To do that, you cannot use M-x debug-on-error, as using the debugger is (rightfully) disabled during post-command-hook.

What you can do is old-school debugging: Add calls to message to the function at various points, printing relevant info, to let you know just what is going on. Simple to do, and generally quick to debug. Open buffer *Messages* in a separate frame, and put point at the end of it, so you can see what's going on.

Have handy a remove-hook sexp or a sexp to restore the un-messaged version of the function (e.g. in the secondary selection or a register), so you can quickly restore things if they get out of hand. ;-)

Drew
  • 75,699
  • 9
  • 109
  • 225
  • I agree. For this specific case, I didn't care about the errors and I wanted that function to work when conditions were valid. – Kaushal Modi Oct 10 '14 at 15:43
  • I understand. But that's not a great thing to do. The less you have on `post-command-hook`, the better. Stuff that performs side effects or takes time, but which has no positive effect, is worth fixing or removing. – Drew Oct 10 '14 at 15:54
  • 2
    I really like the trick at https://lists.gnu.org/archive/html/emacs-devel/2010-07/msg01410.html actually; it lets you use the usual debugger for post-command hooks. – Clément Jan 13 '16 at 07:31
2

The usual debug-on-error doesn't work, but you can make it work :) A convenient way to debug these issues was proposed on emacs-devel back in 2010:

Run toggle-debug-on-error, then advise your function to add an error handler to it:

(defadvice endless/indent-defun (around intercept activate)
  (condition-case err
      ad-do-it
    ((debug error) (signal (car err) (cdr err)))))

This will break into the debugger, just as if you were running the function as usual. The trick is from Johan Bockgård.

Clément
  • 3,924
  • 1
  • 22
  • 37