2

When I'm programming Python, I will use rope to rename variables (using ropemacs). rope-rename pops up a dialogue after you provide a new variable name, where you can preview the change, cancel, or perform the refactoring.

For example:

Choose what to do: [perform]  {perform | preview | cancel}

"perform" is always the default option. 90% of the time, I don't want to go through this menu, I just want to to select the default option.

Is there any way to advise a command to automatically choose a specific (or the default) dialogue option so I can skip this menu? Is there maybe a package that allows me to specify automatic selections in dialogues matching certain conditions?

  • Without seeing the rope code, it's hard to suggest something (to avoid seeing the menu/prompt). But if this "menu" is from completing-read then you should be able to just hit RET (Enter) to get the default choice. – Drew Aug 24 '16 at 17:39
  • 2
    I code by voice, so having to enter extra, single keypresses slows down my workflow a lot more than it would for most people. (I have to manually say "enter," pause, wait for a recognition, then it will enter the command). The rope code is written in Python and mapped to elisp using Pymacs. It doesn't seem to take any inputs that would suppress this menu. – jcaw Aug 24 '16 at 17:41
  • Got it. Someone else, who has the rope code or is familiar with this command, will offer a solution, no doubt. – Drew Aug 24 '16 at 17:42
1

After delving into the innards of the minibuffer, I've developed a solution that should work for all prompting functions. It's pretty hacky though.

This method intercepts the prompt function itself (read-from-minibuffer) and returns the default value - iff the prompt matches one of a list of regular expressions. This could be extended to return a specific value (other than the default), based on the prompt.

This is the code:

;; First, we set up a global list of regular expressions. This
;; variable should only be modified by auto-pick-default-prompt. A
;; prompt that matches any of these regular expressions will be
;; accepted automatically.
(setq auto-pick-default-prompts '())


(defun auto-pick-default-internal (original-function
                                   prompt
                                   &optional initial-contents key-map
                                   read history default-value
                                   inherit-input-method)
  "Function to be run around prompts to auto-pick default value.

Uses the global variable auto-pick-default-prompts to
determine whether the particular prompt it is enclosing should be
automatically confirmed.

If no regular expressions for prompts are specified, auto
confirms all prompts."
  ;; If no prompt filters have been set, just return the default value
  ;; for the prompt
  (if (not auto-pick-default-prompts)
      default-value
    ;; Else check if the prompt matches one of the filters.
    ;; If so, return the default value for the prompt.
    (let ((matches nil))
      (mapc #'(lambda (regexp)
                (if (string-match regexp prompt)
                    (setq matches t)))
            auto-pick-default-prompts)
      (if matches
          default-value
        (funcall original-function
                 prompt initial-contents key-map read history
                 default-value inherit-input-method)))))


(defun auto-pick-default-prompt (function is-interactive prompt-regexps &optional args)
  "Runs a function, auto selecting the default option in prompts.

Takes a list of regular expressions for prompts that should be
auto-confirmed. Prompts which do not match any of these
expressions will not be auto confirmed."
  (condition-case nil
      (progn
        ;; Set the prompts that should be auto-accepted
        (setq auto-pick-default-prompts prompt-regexps)
        ;; Add the intercepting command
        (advice-add 'read-from-minibuffer :around #'auto-pick-default-internal)
        ;; Call the function in the appropriate manner (interactive,
        ;; with arguments, without arguments)
        (if is-interactive
            (if (> (length args) 0)
                (call-interactively function nil args)
              (call-interactively function))
          (apply function args))
        ;; Now remove the intercepting command and reset the prompts
        ;; that should be auto-accepted.
        (advice-remove 'read-from-minibuffer #'auto-pick-default-internal)
        (setq auto-pick-default-prompts nil))
    ((debug error) (progn
                     ;; This function wraps a child function with some
                     ;; advice. If the child throws an error, the
                     ;; advice will not be removed. Explicitly remove
                     ;; advice after an error has been thrown.
                     (advice-remove 'read-from-minibuffer #'auto-pick-default-internal)
                     (setq auto-pick-default-prompts nil)            
                     (signal err)))))


(defun noprompt-rope-rename (&rest args)
  "Call rope-rename, skipping the confirmation prompt."
  (interactive "P")
  (let ((prompts-to-skip'("Choose what to do")))
    (auto-pick-default-prompt 'rope-rename t prompts-to-skip)))

A limitation of this approach is that it can't be called recursively. A command wrapped by auto-pick-default-prompt cannot itself call auto-pick-default-prompt. That should be fine though, and I imagine it's possible to get around this limitation by extending the advice system.

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.