;; Comint Mode Commands: (common to all derived modes, like shell & cmulisp
;; mode)
;;
-;; m-p comint-previous-input Cycle backwards in input history
-;; m-n comint-next-input Cycle forwards
+;; m-p comint-previous-input Cycle backwards in input history
+;; m-n comint-next-input Cycle forwards
;; m-r comint-previous-matching-input Previous input matching a regexp
;; m-s comint-next-matching-input Next input that matches
-;; m-c-l comint-show-output Show last batch of process output
+;; m-c-l comint-show-output Show last batch of process output
;; return comint-send-input
-;; c-d comint-delchar-or-maybe-eof Delete char unless at end of buff
-;; c-c c-a comint-bol Beginning of line; skip prompt
+;; c-d comint-delchar-or-maybe-eof Delete char unless at end of buff
+;; c-c c-a comint-bol-or-process-mark First time, move point to bol;
+;; second time, move to process-mark.
;; c-c c-u comint-kill-input ^u
;; c-c c-w backward-kill-word ^w
;; c-c c-c comint-interrupt-subjob ^c
;; comint-continue-subjob Send CONT signal to buffer's process
;; group. Useful if you accidentally
;; suspend your process (with C-c C-z).
+;; comint-get-next-from-history Fetch successive input history lines
+;; comint-accumulate Combine lines to send them together
+;; as input.
+;; comint-goto-process-mark Move point to where process-mark is.
+;; comint-set-process-mark Set process-mark to point.
;; comint-mode-hook is the comint mode hook. Basically for your keybindings.
;; comint-input-ring-size integer For the input history
;; comint-input-ring ring mechanism
;; comint-input-ring-index number ...
+;; comint-save-input-ring-index number ...
;; comint-input-autoexpand symbol ...
;; comint-input-ignoredups boolean ...
;; comint-last-input-match string ...
;; comint-scroll-to-bottom-on-input symbol For scroll behavior
;; comint-scroll-to-bottom-on-output symbol ...
;; comint-scroll-show-maximum-output boolean ...
+;; comint-accum-marker maker For comint-accumulate
;;
;; Comint mode non-buffer local variables:
;; comint-completion-addsuffix boolean/cons For file name
This variable is buffer-local."
:type '(choice (const :tag "off" nil)
- (const :tag "on" t)
(const input)
- (const history))
+ (const history)
+ (other :tag "on" t))
:group 'comint)
(defcustom comint-input-ignoredups nil
"Index of last matched history element.")
(defvar comint-matching-input-from-input-string ""
"Input previously used to match input history.")
+(defvar comint-save-input-ring-index
+ "Last input ring index which you copied.
+This is to support the command \\[comint-get-next-from-history].")
+
+(defvar comint-accum-marker nil
+ "Non-nil if you are accumulating input lines to send as input together.
+The command \\[comint-accumulate] sets this.")
(put 'comint-replace-by-expanded-history 'menu-enable 'comint-input-autoexpand)
(put 'comint-input-ring 'permanent-local t)
(put 'comint-input-ring-index 'permanent-local t)
+(put 'comint-save-input-ring-index 'permanent-local t)
(put 'comint-input-autoexpand 'permanent-local t)
(put 'comint-input-filter-functions 'permanent-local t)
(put 'comint-output-filter-functions 'permanent-local t)
(or (and (boundp 'comint-input-ring) comint-input-ring)
(setq comint-input-ring (make-ring comint-input-ring-size)))
(make-local-variable 'comint-input-ring-index)
+ (make-local-variable 'comint-save-input-ring-index)
(or (and (boundp 'comint-input-ring-index) comint-input-ring-index)
(setq comint-input-ring-index nil))
+ (or (and (boundp 'comint-save-input-ring-index) comint-save-input-ring-index)
+ (setq comint-save-input-ring-index nil))
(make-local-variable 'comint-matching-input-from-input-string)
(make-local-variable 'comint-input-autoexpand)
(make-local-variable 'comint-input-ignoredups)
(make-local-variable 'comint-process-echoes)
(make-local-variable 'comint-file-name-chars)
(make-local-variable 'comint-file-name-quote-list)
+ (make-local-variable 'comint-accum-marker)
+ (setq comint-accum-marker (make-marker))
+ (set-marker comint-accum-marker nil)
(run-hooks 'comint-mode-hook))
(if comint-mode-map
(define-key comint-mode-map [C-down] 'comint-next-input)
(define-key comint-mode-map "\er" 'comint-previous-matching-input)
(define-key comint-mode-map "\es" 'comint-next-matching-input)
- (define-key comint-mode-map [?\A-\M-r] 'comint-previous-matching-input-from-input)
- (define-key comint-mode-map [?\A-\M-s] 'comint-next-matching-input-from-input)
+ (define-key comint-mode-map [?\C-c ?\M-r] 'comint-previous-matching-input-from-input)
+ (define-key comint-mode-map [?\C-c ?\M-s] 'comint-next-matching-input-from-input)
(define-key comint-mode-map "\e\C-l" 'comint-show-output)
(define-key comint-mode-map "\C-m" 'comint-send-input)
(define-key comint-mode-map "\C-d" 'comint-delchar-or-maybe-eof)
- (define-key comint-mode-map "\C-c\C-a" 'comint-bol)
+ (define-key comint-mode-map "\C-c " 'comint-accumulate)
+ (define-key comint-mode-map "\C-c\C-x" 'comint-get-next-from-history)
+ (define-key comint-mode-map "\C-c\C-a" 'comint-bol-or-process-mark)
(define-key comint-mode-map "\C-c\C-u" 'comint-kill-input)
(define-key comint-mode-map "\C-c\C-w" 'backward-kill-word)
(define-key comint-mode-map "\C-c\C-c" 'comint-interrupt-subjob)
(default-directory
(if (file-accessible-directory-p default-directory)
default-directory
- (char-to-string directory-sep-char))))
- (apply 'start-process name buffer command switches)))
+ (char-to-string directory-sep-char)))
+ proc decoding encoding changed)
+ (setq proc (apply 'start-process name buffer command switches))
+ (let ((coding-systems (process-coding-system proc)))
+ (setq decoding (car coding-systems)
+ encoding (cdr coding-systems)))
+ ;; If start-process decided to use some coding system for decoding
+ ;; data sent form the process and the coding system doesn't
+ ;; specify EOL conversion, we had better convert CRLF to LF.
+ (if (vectorp (coding-system-eol-type decoding))
+ (setq decoding (coding-system-change-eol-conversion decoding 'dos)
+ changed t))
+ ;; Even if start-process left the coding system for encoding data
+ ;; sent from the process undecided, we had better use the same one
+ ;; as what we use for decoding. But, we should suppress EOL
+ ;; conversion.
+ (if (and decoding (not encoding))
+ (setq encoding (coding-system-change-eol-conversion decoding 'unix)
+ changed t))
+ (if changed
+ (set-process-coding-system proc decoding encoding))
+ proc))
\f
;; Input history processing in a buffer
;; ===========================================================================
(message "History item: %d" (1+ pos))
(delete-region
;; Can't use kill-region as it sets this-command
- (process-mark (get-buffer-process (current-buffer))) (point))
+ (or (marker-position comint-accum-marker)
+ (process-mark (get-buffer-process (current-buffer))))
+ (point))
(insert (ring-ref comint-input-ring pos)))))
(defun comint-next-matching-input (regexp arg)
;; Starting a new search
(setq comint-matching-input-from-input-string
(buffer-substring
- (process-mark (get-buffer-process (current-buffer)))
+ (or (marker-position comint-accum-marker)
+ (process-mark (get-buffer-process (current-buffer))))
(point))
comint-input-ring-index nil))
(comint-previous-matching-input
(comint-previous-matching-input-from-input (- arg)))
-(defun comint-replace-by-expanded-history (&optional silent)
+(defun comint-replace-by-expanded-history (&optional silent start)
"Expand input command history references before point.
Expansion is dependent on the value of `comint-input-autoexpand'.
If the optional argument SILENT is non-nil, never complain
even if history reference seems erroneous.
+If the optional argument START is non-nil, that specifies the
+start of the text to scan for history references, rather
+than the logical beginning of line.
+
See `comint-magic-space' and `comint-replace-by-expanded-history-before-point'.
Returns t if successful."
(looking-at comint-prompt-regexp)))
;; Looks like there might be history references in the command.
(let ((previous-modified-tick (buffer-modified-tick)))
- (message "Expanding history references...")
- (comint-replace-by-expanded-history-before-point silent)
+ (comint-replace-by-expanded-history-before-point silent start)
(/= previous-modified-tick (buffer-modified-tick)))))
-(defun comint-replace-by-expanded-history-before-point (silent)
+(defun comint-replace-by-expanded-history-before-point (silent &optional start)
"Expand directory stack reference before point.
-See `comint-replace-by-expanded-history'. Returns t if successful."
+See `comint-replace-by-expanded-history'. Returns t if successful.
+
+If the optional argument START is non-nil, that specifies the
+start of the text to scan for history references, rather
+than the logical beginning of line."
(save-excursion
(let ((toend (- (save-excursion (end-of-line nil) (point)) (point)))
- (start (progn (comint-bol nil) (point))))
+ (start (or start (progn (comint-bol nil) (point)))))
(while (progn
(skip-chars-forward "^!^"
(save-excursion
(replace-match new t t)
(message "History item: substituted"))))
(t
- (goto-char (match-end 0))))))))
+ (forward-char 1)))))))
(defun comint-magic-space (arg)
;; Just whatever's already there
intxt
;; Expand and leave it visible in buffer
- (comint-replace-by-expanded-history t)
+ (comint-replace-by-expanded-history t pmark)
(buffer-substring pmark (point))))
(history (if (not (eq comint-input-autoexpand 'history))
input
;; This is messy 'cos ultimately the original
;; functions used do insertion, rather than return
;; strings. We have to expand, then insert back.
- (comint-replace-by-expanded-history t)
+ (comint-replace-by-expanded-history t pmark)
(let ((copy (buffer-substring pmark (point)))
(start (point)))
(insert input)
(ring-insert comint-input-ring history))
(run-hook-with-args 'comint-input-filter-functions
(concat input "\n"))
+ (setq comint-save-input-ring-index comint-input-ring-index)
(setq comint-input-ring-index nil)
;; Update the markers before we send the input
;; in case we get output amidst sending the input.
(set-marker comint-last-input-start pmark)
(set-marker comint-last-input-end (point))
(set-marker (process-mark proc) (point))
+ ;; clear the "accumulation" marker
+ (set-marker comint-accum-marker nil)
(funcall comint-input-sender proc input)
;; This used to call comint-output-filter-functions,
;; but that scrolled the buffer in undesirable ways.
(and (eq scroll 'this) (eq selected window))
(and (eq scroll 'others) (not (eq selected window)))
;; If point was at the end, keep it at end.
- (>= (point) comint-last-output-start)))
+ (and (marker-position comint-last-output-start)
+ (>= (point) comint-last-output-start))))
(goto-char (process-mark process)))
;; Optionally scroll so that the text
;; ends at the bottom of the window.
directory tracking functions.")
(defvar comint-file-name-chars
- (cond
- ((eq system-type 'ms-dos)
- "~/A-Za-z0-9_^$!#%&{}@`'.()-")
- ((eq system-type 'windows-nt)
- "~/A-Za-z0-9_^$!#%&{}@`'.,:()-")
- (t
- "~/A-Za-z0-9+@:_.$#%,={}-"))
+ (if (memq system-type '(ms-dos windows-nt))
+ "~/A-Za-z0-9_^$!#%&{}@`'.,:()-"
+ "~/A-Za-z0-9+@:_.$#%,={}-")
"String of characters valid in a file name.
Note that all non-ASCII characters are considered valid in a file name
regardless of what this variable says.
(set-window-configuration conf)
(setq unread-command-events (listify-key-sequence key)))))))
\f
+(defun comint-get-next-from-history ()
+ "After fetching a line from input history, this fetches the following line.
+In other words, this recalls the input line after the line you recalled last.
+You can use this to repeat a sequence of input lines."
+ (interactive)
+ (if comint-save-input-ring-index
+ (progn
+ (setq comint-input-ring-index (1+ comint-save-input-ring-index))
+ (comint-next-input 1))
+ (message "No previous history command")))
+
+(defun comint-accumulate ()
+ "Accumulate a line to send as input along with more lines.
+This inserts a newline so that you can enter more text
+to be sent along with this line. Use \\[comint-send-input]
+to send all the accumulated input, at once.
+The entire accumulated text becomes one item in the input history
+when you send it."
+ (interactive)
+ (insert "\n")
+ (set-marker comint-accum-marker (point))
+ (if comint-input-ring-index
+ (setq comint-save-input-ring-index
+ (- comint-input-ring-index 1))))
+
+(defun comint-goto-process-mark ()
+ "Move point to the process mark.
+The process mark separates output, and input already sent,
+from input that has not yet been sent."
+ (interactive)
+ (let ((proc (or (get-buffer-process (current-buffer))
+ (error "Current buffer has no process"))))
+ (goto-char (process-mark proc))
+ (message "Point is now at the process mark")))
+
+(defun comint-bol-or-process-mark ()
+ "Move point beginning of line (after prompt) or to the process mark.
+The first time you use this command, it moves to the beginning of the line
+\(but after the prompt, if any). If you repeat it again immediately,
+it moves point to the process mark.
+
+The process mark separates the process output, along with input already sent,
+from input that has not yet been sent. Ordinarily, the process mark
+is at the beginning of the current input line; but if you have
+used \\[comint-accumulate] to send multiple lines at once,
+the process mark is at the beginning of the accumulated input."
+ (interactive)
+ (if (not (eq last-command 'comint-bol-or-process-mark))
+ (comint-bol nil)
+ (comint-goto-process-mark)))
+
+(defun comint-set-process-mark ()
+ "Set the process mark at point."
+ (interactive)
+ (let ((proc (or (get-buffer-process (current-buffer))
+ (error "Current buffer has no process"))))
+ (set-marker (process-mark proc) (point))
+ (message "Process mark set")))
+
+\f
;; Converting process modes to use comint mode
;; ===========================================================================
;; The code in the Emacs 19 distribution has all been modified to use comint