8

I made a custom function that combines two functions of twittering-mode , twittering-favorite and twittering-native-retweet, however these two needs input from me by answering an yes or no question.

I want to know if there is a way to wrap those those two functions with something that will make them receive an answer without my direct intervention.

  • 8
    I don't use twittering-mode (and I won't bother to access the code), but as a general word of advice: Typically, instead of doing what you suggest (make code that simulates a user answering yes) it is better to make code that directly uses the code that expects the answer. IOW, try leveraging the source code path that a yes answer would cause to be invoked. (Just a suggestion.) – Drew Dec 25 '15 at 23:55
  • The title is misleading as this cannot be done properly in a generic way. – wasamasa Dec 26 '15 at 6:40
  • Related: emacs.stackexchange.com/questions/14669/… – YoungFrog Aug 16 '16 at 11:51
7

EDIT: As @hatschipuh pointed out in the comments, an flet-type construction is more straightforward and doesn't rely on my idiosyncratic advice macro. At least on my Emacs (24.5.1), cl-flet uses lexical scoping, so you'll need the noflet package for the following snippet to work. Scroll down for the original, idiosyncratic answer.

(defun my/bypass-confirmation (function &rest args)
  "Call FUNCTION with ARGS, bypassing all `y-or-n-p' prompts."
  (require 'noflet)
  (noflet
      ((y-or-n-p (prompt) t))
    (apply function args)))

(defun my/bypass-confirmation-all (function &rest args)
  "Call FUNCTION with ARGS, bypassing all prompts.
This includes both `y-or-n-p' and `yes-or-no-p'."
  (require 'noflet)
  (noflet
      ((y-or-n-p    (prompt) t)
       (yes-or-no-p (prompt) t))
    (apply function args)))

EDIT: This is the original answer, except that I fixed my/bypass-confirmation-all to work as advertised and changed the calling conventions a bit.

Here's a general wrapper that should work for any function.

(defun my/bypass-confirmation (function &rest args)
  "Call FUNCTION with ARGS, bypassing all `y-or-n-p' prompts."
  (my/with-advice
      ((#'y-or-n-p :override (lambda (prompt) t)))
    (apply function args)))

(defun my/bypass-confirmation-all (function &rest args)
  "Call FUNCTION with ARGS, bypassing all prompts.
This includes both `y-or-n-p' and `yes-or-no-p'."
  (my/with-advice
      ((#'y-or-n-p    :override (lambda (prompt) t))
       (#'yes-or-no-p :override (lambda (prompt) t)))
    (apply function args)))

This code depends on this macro, which seems to be my go-to solution for everything on Stackexchange.

(defmacro my/with-advice (adlist &rest body)
  "Execute BODY with temporary advice in ADLIST.

Each element of ADLIST should be a list of the form
  (SYMBOL WHERE FUNCTION [PROPS])
suitable for passing to `advice-add'.  The BODY is wrapped in an
`unwind-protect' form, so the advice will be removed even in the
event of an error or nonlocal exit."
  (declare (debug ((&rest (&rest form)) body))
           (indent 1))
  `(progn
     ,@(mapcar (lambda (adform)
                 (cons 'advice-add adform))
               adlist)
     (unwind-protect (progn ,@body)
       ,@(mapcar (lambda (adform)
                   `(advice-remove ,(car adform) ,(nth 2 adform)))
                 adlist))))

Whether this code is the smartest way to handle this situation, I don't know. In general, I like using this sort of temporary advice to make modifications of existing functions instead of duplicating the original functions' code, in part because it helps to future-proof your modified function against unrelated changes in the original. But in this case you may need to take additional care, because if twittering-mode updates and changes the prompts or adds an additional one, you won't see the changes. Since a y-or-n prompt indicates a controversial choice, that could have unfortunate consequences.


EDIT: It occurred to me that an example of use might be helpful. This example works with either implementation.

(defun my/twittering-function ()
  ;; This will bypass `y-or-n-p' in both commands.
  (my/bypass-confirmation #'twittering-favorite arg)
  (my/bypass-confirmation #'twittering-native-retweet)
  ;; This will bypass both `y-or-n-p' and `yes-or-no-p' in this command.
  (my/bypass-confirmation-all #'twittering-favorite arg)
  ;; Prompts in this call are not bypassed.
  (twittering-native-retweet)
  • Wouldn't this modify the behavior of the functions I would like to have behaving differently (only) inside my custom function? – shackra Dec 26 '15 at 7:23
  • Yes, isn't that what you want? – Aaron Harris Dec 26 '15 at 7:48
  • Well, not exactly, changing the behavior of both commands everywhere is something I don't feel comfortable with :( – shackra Dec 26 '15 at 20:03
  • 1
    I think I may have misread your earlier comment, then. The only prompts bypassed are those inside the wrapped function call. To help clarify, I added a usage example to the answer. – Aaron Harris Dec 26 '15 at 22:12
  • 1
    The following achieves basically the same and is a good alternative I think: (flet ((yes-or-no-p (prompt) t) (y-or-n-p (prompt) t)) body...) – clemera Dec 28 '15 at 10:50

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.