Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way in elisp to trap an error case

Tags:

emacs

elisp

I'm trying to augment the etags-select functions so it will fall-back to a normal find-tag if find-tag at point failed. The code I've tried is:

(defun my-etags-find-tag ()
  "Find at point or fall back"
  (interactive)
  (unless (etags-select-find-tag-at-point)
    (etags-select-find-tag)))

(global-set-key (kbd "C-f") 'my-etags-find-tag)

However this fails when point is not at a valid tag. Instead I get a error thrown by etags-select-find-tag-at-point:

etags-select-find-tag-at-point: Wrong type argument: char-or-string-p, nil

In this case I just have to repeat the test done by etags-select-find-tag-at-point:

(defun my-etags-find-tag ()
  "Find at point or fall back"
  (interactive)
  (if (find-tag-default)
      (etags-select-find-tag-at-point)
    (etags-select-find-tag)))

But it does seem a little redundant. Is it possible to trap exceptions and do alternate processing in elisp?

like image 453
stsquad Avatar asked Jul 20 '12 11:07

stsquad


2 Answers

Try ignore-errors; eg,

(unless (ignore-errors (etags-select-find-tag-at-point))
  (etags-select-find-tag))

Normally, (ignore-errors body) returns whatever body returns; when there's error, it returns nil.

Also look at condition-case for more general condition handling.

If you have Elisp info manual installed, you can get more details from C-hSignore-errors.

Edit:

I failed to consider the possibility that the function may return nil on success; so we probably need

(unless (ignore-errors (or (etags-select-find-tag-at-point) t))
  (etags-select-find-tag))
like image 171
huaiyuan Avatar answered Sep 22 '22 23:09

huaiyuan


Without modifying the original source code of etags-select.el, I see it the more reasonable option, even when it calls twice to find-tag-default. You can cheat the dynamic environment within the call to avoid the repetition of the call by memoizing it with something like:

(defun my-etags-find-tag ()
  "Find at point or fall back"
  (interactive)
  (let ((ftd (find-tag-default)))
    (flet ((find-tag-default () ftd))
      (if (find-tag-default)
          (etags-select-find-tag-at-point)
        (etags-select-find-tag)))))

EDIT: OK, as per your request, an explanation of the code. First, note that this code achieves both questions:

  1. It does not fail
  2. It is more efficient than the code you show (the one you say it is redundant).

Why is it more efficient? The problem with your redundant code is that you call find-tag-default to see if it is nil, and, if it is, you call etags-select-find-tag-at-point. This function calls again to find-tag-default to obtain a default value. What my code does is to cache the value of find-tag-default by redefining the function by being just the value you calculated. The flet does that, so when etags-select-find-tag-at-point calls find-tag-default, the calculated value is returned without any further processing.

like image 36
Diego Sevilla Avatar answered Sep 21 '22 23:09

Diego Sevilla