1

I'd like to make my up-arrow key from within eshell be eshell-previous-matching-input-from-input, as it is, when point is at point-max, but be previous-line otherwise. I've written


    (defun my-up-arrow-in-eshell() (interactive) 
      (if (= (point) (point-max)) 
          (eshell-previous-matching-input-from-input)
      ; else
        (previous-line)
      )
    )

    (add-hook 'eshell-mode-hook
      (lambda ()
        (define-key eshell-mode-map (kbd "&ltup>") 'my-up-arrow-in-eshell)))

but that's not right, as eshell-previous-matching-input-from-input requires an argument. I can hardcode that to a 0, but that works for a single press of the up-arrow key (when at point-max). I want it to work just like out of the box, when at point-max. What do I give for the argument?

2 Answers2

2

eshell-previous-matching-input-from-input is implemented in a way that relies on last-command to correctly navigate through the input history. Binding up to a new function which then calls eshell-previous-matching-input-from-input therefore does not work as expected with the current implementation.

If you don't want to completely reimplement eshell-previous-matching-input-from-input you could also advise the existing function as follows:

(advice-add 'eshell-previous-matching-input-from-input
        :before-until
        (lambda (&rest r)
          (when (and (eq this-command 'eshell-previous-matching-input-from-input)
             (/= (point) (point-max)))
        (previous-line) t)))
martin_joerg
  • 1,153
  • 1
  • 13
  • 22
  • This is a great answer! Surprising there was no upvotes. I gave a +1 just now! I looked at your profile and saw you committed to the Protein Modeling proposal on Area51. Sorry that it didn't succeed. I proposed a [Materials Modeling](https://area51.stackexchange.com/proposals/122958/materials-modeling?referrer=NzE1MWZiMjg1NmE1MDU4YWQ2ODkzMzZiNGY5OTRkNWRhN2JkNzdhZGUwODllOWUxNGNjZjRhZjBmYTE3M2M4ZBljSouiYXUzpNjPv6N_DNmpFSwSGHCb4w8-XBwHc-_E0) site which covers protein modeling, but also other materials like solar cells, photo-voltaics, energy storage materials, new developments in batteries, – Nike Feb 15 '20 at 02:24
  • and lighter or stronger materials for cars, airplanes, spaceships, etc. It would be very lovely to have you in the Private Beta! Please commit if you don't think it would be inconvenient! – Nike Feb 15 '20 at 02:24
1

You can use (call-interactively #'eshell-previous-matching-input-from-input) to have the argument interpreted according to its interactive form, eg.

(defun my-up-arrow-in-eshell ()
  (interactive) 
  (if (/= (point) (point-max))
      (previous-line)
    (setq this-command 'eshell-previous-matching-input-from-input)
    (call-interactively #'eshell-previous-matching-input-from-input)))

Alternatively, you could add your own argument and pass it along, eg.

(defun my-up-arrow-in-eshell (arg)
  (interactive "p") 
  (if (= (point) (point-max)) 
      (progn
        (setq this-command 'eshell-previous-matching-input-from-input)
        (eshell-previous-matching-input-from-input arg))
    (previous-line arg)))

A final option could be a conditional binding (see (elisp)Extended Menu Items), where eshell-previous-matching-input-from-input is bound when the point is at point-max

(define-key eshell-hist-mode-map (kbd "<up>")
  '(menu-item "maybe-hist"
              nil
              :filter
              (lambda (&optional _)
                (when (= (point) (point-max))
                  'eshell-previous-matching-input-from-input))))
Rorschach
  • 31,301
  • 5
  • 78
  • 129
  • I tried both your first and your second and neither of them are correctly moving to the next-to-last input when the up-arrow key is hit the second time. – Steve Biederman Nov 26 '19 at 23:19
  • @SteveBiederman I didn't realize that was how it worked (special behaviour on successive invocations) -- see update – Rorschach Nov 27 '19 at 00:06