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)
4
  • 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, 2014 at 14:41
  • @Dan I have updated the question will full code. Oct 10, 2014 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, 2014 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. Oct 10, 2014 at 15:40

3 Answers 3

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...

4
  • 1
    I believe that the question then I need to ask is how to make that function not throw an error. Oct 10, 2014 at 15:11
  • (when (and l r) ....)
    – tarsius
    Oct 10, 2014 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. Oct 10, 2014 at 15:15
  • I have removed my speculation on what is causing the error - that was obviously wrong.
    – tarsius
    Oct 10, 2014 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. ;-)

3
  • I agree. For this specific case, I didn't care about the errors and I wanted that function to work when conditions were valid. Oct 10, 2014 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, 2014 at 15:54
  • 2
    I really like the trick at 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, 2016 at 7: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.

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.