1

I apologize if this is a duplicate, but the essence of the question is whether it is possible to create "around" advice for an existing function and bind that to a new one.

In my case, I'm trying to change how evil-delete and similar functions handle the kill ring, namely by inserting into the second position instead of the first. I already have a function that accomplishes this, called yf-kill-new-second-pos, however I cannot figure out how to cleanly define a derivative of evil-delete that uses this instead of kill-new without either copying and pasting or (I admit I haven't tried this) advising evil-delete, which would undesirably change it's functionality.

I attempted to solve the issue by using symbol-function to grab the source for evil-delete and then wrapping that in an flet to redefine kill-new, but that did nothing to change the function's behavior (even when set to nil). Code:

(evil-define-operator yf-d (beg end type register yank-handler)
  "Evil-delete that dumps to 2nd in kill ring by default"
  ;;Same interactive clause as evil-delete
  (interactive "<R><x><y>")
  (cl-flet ((kill-new #'yf-kill-new-second-pos))
    (funcall (symbol-function 'evil-delete) beg end type register)))

;;testing measure 
(bind-key (kbd "<f7>") 'yf-d)

This may not be changing anything because evil-delete is byte-compiled, but I'm not entirely sure. It could also have something to do with evil-define-operator, but again, I don't know how to test around this. Any help in solving this issue would be greatly appreciated :)

  • You ask "whether it is possible to create "around" advice for an existing function and bind that to a new one". Yes. Did you try it? an "around" advice lets you completely replace the behavior of the function. – Drew Sep 9 '17 at 23:08
1

I attempted to solve the issue by ... wrapping that in an flet to redefine kill-new ...

Except you actually used cl-flet which is quite different.

(cl-flet ((kill-new #'yf-kill-new-second-pos))
  (evil-delete beg end type register))

cl-flet creates a local function definition which is visible only (and non-recursively) to its body code. Functions called by that body code do not see it. As kill-new is not called directly by the body code, this usage of cl-flet has no practical effect.

flet, OTOH, creates function overrides which are visible for the entire scope of the form, so if that call to evil-delete ultimately causes kill-new to be called, it would be your function which was called.

(flet ((kill-new (string &optional replace)
                 (yf-kill-new-second-pos string replace)))
  (evil-delete beg end type register))

These days flet is marked as deprecated, but there's an analogous way to do the same thing with cl-letf:

(cl-letf (((symbol-function 'kill-new) #'yf-kill-new-second-pos))
  (evil-delete beg end type register))

Now I don't know how you've defined yf-kill-new-second-pos, but obviously you don't want a dynamic binding for kill-new which calls kill-new, so you might consider advising kill-new itself:

(defvar my-kill-2nd)

(defadvice kill-new (around my-kill-new-2nd)
  "If `my-kill-2nd' is non-nil, kills go to the second position of the `kill-ring'."
  (if (and kill-ring (bound-and-true-p my-kill-2nd))
      (let ((real-kill-ring kill-ring)
            (kill-ring (cdr kill-ring)))
        ad-do-it
        (setcdr real-kill-ring kill-ring))
    ad-do-it))

(ad-activate 'kill-new)

(let ((my-kill-2nd t))
  (evil-delete beg end type register))
  • Thank you sou much! I wasn't aware of how precisely cl-flet worked, nor cl-letf. Here is the code of my function for future reference. pastebin.com/s254NQSZ – Your Fin Sep 10 '17 at 17:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.