The current accepted answer satisfies the stated requirements, but has two major limitations:
- 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.
- 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:
- If
point
is not already on the last line, then it is moved to point-max
(which is always read-write).
- 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)