Emacs shell-mode: Prevent RET sending input from anywhere

425 Views Asked by At

As the documentation says that RET will comint-send-input anywhere in a shell mode. The issue is that if you by mistake hit enter on any line and you are not at a prompt it will execute the whole random text until the next prompt. How can I prevent this from happening? It would be nice if hitting Enter anywhere out of the prompt will send you to a new prompt at the bottom.

2

There are 2 best solutions below

5
On BEST ANSWER

Something like this?

(defun my-comint-send-input-maybe ()
  "Only `comint-send-input' when point is after the latest prompt.

Otherwise move to the end of the buffer."
  (interactive)
  (let ((proc (get-buffer-process (current-buffer))))
    (if (and proc (>= (point) (marker-position (process-mark proc))))
        (comint-send-input)
      (goto-char (point-max)))))

(with-eval-after-load "comint"
  (define-key shell-mode-map [remap comint-send-input] 'my-comint-send-input-maybe))

You could replace (goto-char (point-max)) with (comint-copy-old-input) to insert but not send the old input at the new prompt; but that's still liable to cause problems when the inserted input looks like output.

However, also note the comments and link in C-hf comint-send-input regarding comint-get-old-input -- this can be used to implement custom logic for establishing what the "old input" should be when comint-send-input is invoked with point before the process mark.

0
On

Bulletproof:

(defun comint-send-input-or-insert-previous-input ()
  "Call `comint-send-input' if point is after the process output marker.
Otherwise, move point to the process mark and try to insert a previous input
from `comint-input-ring' (if any) returned by `comint-previous-input-string'
and affected by the current value of `comint-input-ring-index'.

Implementation is synthesized from and inspired by the `comint-after-pmark-p',
`comint-goto-process-mark', and `comint-copy-old-input' functions."
  (interactive)
  (let ((process (get-buffer-process (current-buffer))))
    (if (not process)
        (user-error "Current buffer has no process")
      (let ((pmark (process-mark process)))
        (if (<= (marker-position pmark) (point))
            (comint-send-input)
          (goto-char pmark)
          (when (and (eolp) comint-input-ring)
            (let ((input (comint-previous-input-string 0)))
              (when (char-or-string-p input)
                (insert input)))))))))