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?
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
.
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))
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With