1

Is it possible to make the first history item available as the default argument when running commands like eval-expression and goto-line?

I'd like to be able to just press enter to use the previous value.

I started writing a wrapper around goto-line but thought there must be a more general solution.

To be clearer, here's an example:

  1. I run goto-line, type 236 and press enter.
  2. I edit around for some time.
  3. I run goto-line again and I want to just press enter to go to line 236.

I use helm for M-x and C-x b, but there does not seem to be helm support for these other commands.

2
  • Are you aware of savehist-mode? Then you can get the last command by pressing arrow up. AFAIK, vertico, by default, always selects the 'last in history' as first candidate (so that it would give you the functionality you ask for). I guess if you'd like to write functionality yourself, that you should probably look at the minibuffer-setup-hook and the recentf-list... Dec 15, 2022 at 15:31
  • Thanks @dalanicolai. savehist seems to be only for saving across sessions. vertico looks like it drops down the history under the prompt, but I want the prompt to stay at the bottom.
    – Matt
    Dec 15, 2022 at 15:55

2 Answers 2

1

I am not sure if this will cause any problems when calling some other functions (it is pefectly save to try it), but as mentioned by Drew already, you could advise the 'underlying' functions. For goto-line the following advice should do the trick:

(defun goto-line-advice-default-last (orig-fun &rest args)
  (when-let (hist (nth 2 args))
    (setf (nth 1 args) (string-to-number (car (eval hist)))))
  (apply orig-fun args))

(advice-add 'read-number :around #'goto-line-advice-default-last)

(note that the default value is displayed in the prompt, but/so you can just press RET)

And for eval-expression, the following advice should do it:

(defun eval-expression-advice-default-last (orig-fun &rest args)
  ;; only for eval-expression (so this is configurable)
  (when (string-match-p (car args) "Eval: ")
    (when-let (hist (nth 4 args))
      (if (eq (length args) 5)
          (add-to-list 'args nil t (lambda (a b))))
      (setf (car args) (format "Eval [%s]: " (car (eval hist))))
      (setf (nth 5 args) (car (eval hist)))))
  (apply orig-fun args))

(advice-add 'read-from-minibuffer :around #'eval-expression-advice-default-last)

You can configure where the advice applies via the first conditional (here I am using a when but you could also use an unless, see also the edit history for earlier versions).

Of course, you could additionally remove the item(s) from the history. If you really want that, I'll leave it for you as a nice little lisp exercise :)

11
  • 1
    You mean (advice-add 'read-number :around #'goto-line-advice-default-last), right?
    – NickD
    Dec 15, 2022 at 21:25
  • Right! Probably a few too many undo's before copy pasting... thanks again! Dec 15, 2022 at 21:29
  • Thanks @dalanicolai, that helped. This does what I want: (defun goto-line-advice-default-last (orig-fun &rest args) (unless (nth 2 args) (let ((hist (car minibuffer-history))) (and hist (or (eq hist "0") (> (string-to-number (car minibuffer-history)) 0)) (setf (nth 1 args) (string-to-number (car minibuffer-history)))))) (apply orig-fun args))
    – Matt
    Dec 16, 2022 at 6:43
  • I guess I'm better off making wrappers around these functions that handle the input. Especially for eval-expression which will have to access command-history.
    – Matt
    Dec 16, 2022 at 6:45
  • I am not sure what you mean by that last comment. Of course, the advice already wraps around the functions, you can just modify it to your needs. The answer provides a solution to your question as asked (as I don't know your further requirements). Also, I am not sure why you'd need command-history instead of read-expression-history (the (nth 4 args)) here. Maybe you can explain what does not work about the answer? Dec 16, 2022 at 8:35
1

[I edited the tags and title: The question is not about the prompt; it's about providing a default value when reading from the minibuffer. That the default is generally shown in the prompt is something else. If no default value has been provided then none will appear in the prompt.]

Whether there's a default value (or several), and what it is, is determined by the read function call (read-from-minibuffer, completing-read etc.), i.e., by the programmer who wrote that call. While reading, it's available in variable minibuffer-default (the value is put there by read-from-minibuffer C code).

You could conceivably advise some basic read functions to add your own chosen default value, but why?

What default value would you want to add, when there isn't one? And when: during the read? And how: interactively or with Lisp? Do you want to impose your own default value, regardless of what's being read? If so, on what basis would you pick that value? Exactly what behavior are you looking for?

If the read function call doesn't provide a default value then you should consider that to be by design (the programmer's choice). You can, however, send a suggestion to the maintainer of the code that makes that function call, suggesting provision of a default value.


On the other hand, you could add one or more values to the value of minibuffer-history-variable using minibuffer-with-setup-hook. Then you could use M-p to access those values. But you'd either have to do that for an individual read function call or you'd have to advise such a read function.

7
  • Thanks Drew. At least for goto-line and eval-expression I want the default to be the first item in the history. Why, because I'm super annoyed having to type so much ;) It's fine if it's hacky, it just needs to work for me. Will look closer at advising functions, was hoping someone would have done this already.
    – Matt
    Dec 15, 2022 at 17:05
  • You can always use M-p to insert elements from the history list. If you're asking now how to get the first element of the history list to be displayed in the prompt, that's something else. You can pose that as a separate question. (I don't have a good answer for that, but maybe someone else does.)
    – Drew
    Dec 15, 2022 at 17:44
  • I think I've mixed up the "default" concepts used by read-number and read-from-minibuffer which has made my question confusing. I'm trying to save typing M-p. Basically looking for this type of behaviour (read-number "Goto line: " (read (car minibuffer-history))) with some checks that there's a number on the history. I'll have to come back to this.
    – Matt
    Dec 15, 2022 at 18:14
  • In any case, please don't "evolve" your question, moving the goal post, especially if there are answers. You can delete the question and pose a different one, however.
    – Drew
    Dec 15, 2022 at 19:08
  • Maybe I phrased it badly but I did not "evolve" the question. It's the same goal post from the beginning: "I'd like to be able to just press enter to use the previous value."
    – Matt
    Dec 15, 2022 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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