2

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.

phils
  • 71,335
  • 11
  • 153
  • 198
Yuki
  • 3,857
  • 5
  • 25
  • 43

2 Answers2

5

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.

phils
  • 71,335
  • 11
  • 153
  • 198
  • This works like a charm. Thank you. I did make a replacement to `comint-get-old-input`, it is much more convenient. If by mistake I hit `RET` I can easily delete it, if I want execute some previous input I am able to do that. – Yuki Sep 07 '18 at 09:37
  • I was just thinking, how can I test if current line is output of some command or an old prompt. Because even better could be this logic `(if (command output) (goto-char (point-max)) (comint-send-input))`. – Yuki Sep 07 '18 at 09:51
  • I guess the key thing is that you'd need to differentiate the point between the end of a command and the beginning of the resulting output (if any). I don't know offhand whether that's currently supported. If not, you'd need to track those positions yourself. – phils Sep 07 '18 at 10:43
  • `M-x apropos RET comint-last RET` would be of interest, but you'd need to read the code to confirm how those variables are used and when they're reliably available. – phils Sep 07 '18 at 10:51
  • @phils, see my take on this. – Alexander Shukaev Jan 10 '19 at 12:56
1

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)))))))))
Alexander Shukaev
  • 16,674
  • 8
  • 70
  • 85