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.

Drew
  • 75,699
  • 9
  • 109
  • 225
shackra
  • 2,702
  • 18
  • 47
  • 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 06:40
  • Related: http://emacs.stackexchange.com/questions/14669/sort-of-autoreply-for-specific-messages-in-minibuffer/14676#14676 – YoungFrog Aug 16 '16 at 11:51

1 Answers1

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)
Aaron Harris
  • 2,664
  • 17
  • 22
  • 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 07:23
  • Yes, isn't that what you want? – Aaron Harris Dec 26 '15 at 07: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
  • @hatschipuh In principle, yes, but at least on my instance `cl-flet` appears to use lexical scope, and this needs dynamic scope. Updating the answer to incorporate this now. – Aaron Harris Dec 28 '15 at 15:37
  • Ah yes, the `cl-lib` uses lexical scope, the old `cl` library uses dynamic scope for flet. I did not knew about the noflet package. – clemera Dec 28 '15 at 18:18
  • See also this for alternatives to get the old behaviour of flet: http://emacs.stackexchange.com/a/3452/9198 – clemera Dec 28 '15 at 18:24
  • The `noflet` package has seen been superseded by `letf` which is in Emacs core (note, `flet` and `letf` are totally different for what I assume seemed like a good reason at the time). – Resigned June 2023 Jan 24 '17 at 05:21