0
votes

I use evil-mode on emacs, and recently I started using eshell, I really like how I can leave insert mode and move on the eshell buffer to copy content or other goodies, but when entering insert mode again it does it in the cursor current position, what I would like is that when I enter insert mode automatically move the currsor to the prompt line (last line, end of line).

What I did was:

(add-hook 'eshell-mode-hook
      (lambda()
         (define-key evil-normal-state-map (kbd "i") (lambda () (interactive) (evil-goto-line) (evil-append-line nil)))))

However it applies this mapping in all other buffers, I just want to make it active on an eshell buffer.

How to define a key binding that works differently in eshell?

2
Does this link help any?: stackoverflow.com/a/26587651/2112489 Perhaps there are some other evil local maps you can use. I don't use evil, but that's the general idea -- i.e., using local stuff.lawlist

2 Answers

2
votes

The current accepted answer satisfies the stated requirements, but has two major limitations:

  1. It only triggers when entering insert mode with i. Jumping to the last line with I, A, a, or any custom functions/keybindings would require additional scripting.
  2. If point is already on the last line (e.g., when editing the current command), there is no way to enter insert mode at the current position; i is effectively rebound to A.

The first limitation can be eliminated by hooking first on eshell-mode then second on evil-insert-state-entry.

The second limitation can be addressed by setting point's position based first on the line number and second on the read-only text-property:

  1. If point is not already on the last line, then it is moved to point-max (which is always read-write).
  2. Otherwise if the text at point is read-only, point is moved to the position in the current line where the read-only text-property changes.

The following code negates the limitations of the accepted answer.

(defun move-point-to-writeable-last-line ()
  "Move the point to a non-read-only part of the last line.
If point is not on the last line, move point to the maximum position
in the buffer.  Otherwise if the point is in read-only text, move the
point forward out of the read-only sections."
  (interactive)
  (let* ((curline (line-number-at-pos))
         (endline (line-number-at-pos (point-max))))
    (if (= curline endline)
        (if (not (eobp))
            (let (
                  ;; Get text-properties at the current location
                  (plist (text-properties-at (point)))
                  ;; Record next change in text-properties
                  (next-change
                   (or (next-property-change (point) (current-buffer))
                       (point-max))))
              ;; If current text is read-only, go to where that property changes
              (if (plist-get plist 'read-only)
                  (goto-char next-change))))
      (goto-char (point-max)))))

(defun move-point-on-insert-to-writeable-last-line ()
  "Only edit the current command in insert mode."
  (add-hook 'evil-insert-state-entry-hook
        'move-point-to-writeable-last-line
        nil
        t))

(add-hook 'eshell-mode-hook
      'move-point-on-insert-to-writeable-last-line)
2
votes

Thanks to @lawlist for pointing me in the right direction, the solution is just as easy as:

;; Insert at prompt only on eshell
(add-hook 'eshell-mode-hook
      '(lambda ()
         (define-key evil-normal-state-local-map (kbd "i") (lambda () (interactive) (evil-goto-line) (evil-append-line nil)))))

Thanks!