reddit / emacs

Is there a way to execute a function's advice *even when* the function gets quit?

andyjda · 2022-11-14 01:16
Here's what I'm trying to do: I've been using relative line numbers, which are great for moving *x amount* of lines up/down, especially in large files. On occasion, though, I'll need to move to a specific line number (for example, if reading about a line from documentation or an error buffer). In those situations, I want to see all the absolute line numbers. My solution has been: (advice-add 'goto-line-read-args :before (lambda () (setq display-line-numbers 'absolute))) (advice-add 'goto-line :after (lambda (_LINE &optional _BUFFER _RELATIVE) (setq display-line-numbers 'relative))) This works perfectly. However, some times I change my mind after calling `goto-line`, and decide to do something else instead. When I quit out of `goto-line` (`C-g`), the second advice doesn't get run and I'm stuck with absolute line numbers. Obviously it's not much of a pain to set them back to relative, but I'm wondering if there's a way to do it automatically. I'm also asking because I'm trying to get more familiar with how the advising functionality works, and I'd like to understand if there's a way to get out the `quit` issue. It seems to me that sometimes there are advices that **need to run**, even if the function has been quit. Is there a way to make sure that happens?
eleven_cupfuls · 2022-11-14 01:37
Using `:around` advice instead, and let-binding `display-line-numbers` would do it, I think: (defun adj/:around-goto-line-read-args (origfn line &optional buffer _relative) (let ((display-line-numbers 'absolute)) (funcall origfn line buffer nil))) (advice-add 'goto-line-read-args :around #'adj/:around-goto-line-read-args) If that doesn't work for some reason, still `:around` advice, but use `condition-case` to catch the `'quit` signal from `keyboard-quit` and do the cleanup `setq`.
nv-elisp · 2022-11-14 01:57
Sounds like an unwind-protect would work better
andyjda · 2022-11-14 02:09
Thanks so much! This was almost perfect. Small thing is that `goto-line-read-args` doesn't take any arguments, so this works: (defun adj/:around-goto-line-read-args (origfn) (let ((display-line-numbers 'absolute)) (funcall origfn))) (advice-add 'goto-line-read-args :around #'adj/:around-goto-line-read-args)
andyjda · 2022-11-14 02:12
What advantage would `unwind-protect` add? it looks like it'd be a bit more verbose than the let-binding solution
eleven_cupfuls · 2022-11-14 02:20
Oh, right, good point, because you need to reset it in the success case too.
eleven_cupfuls · 2022-11-14 02:21
Gotcha; I included those args based on your `:after` advice which I now see I misread :)
nv-elisp · 2022-11-14 02:44
You're right, the lexical binding is simpler. I misread the example on my phone.
7890yuiop · 2022-11-14 03:31
Not lexical (it wouldn't work if it were). Was maybe a typo for `let`?
nv-elisp · 2022-11-14 04:32
I'm firing on all cylinders today