1
votes

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

2 Answers

2
votes

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)))
1
votes

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))))