;;; m-s comint-next-matching-input Next input that matches
;;; m-c-l comint-show-output Show last batch of process output
;;; return comint-send-input
-;;; 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 Beginning of line; skip prompt
;;; c-c c-u comint-kill-input ^u
;;; c-c c-w backward-kill-word ^w
;;; c-c c-c comint-interrupt-subjob ^c
;;; c-c c-h comint-dynamic-list-input-ring List input history
;;;
;;; Not bound by default in comint-mode (some are in shell mode)
+;;; comint-run Run a program under comint-mode
;;; send-invisible Read a line w/o echo, and send to proc
;;; comint-dynamic-complete-filename Complete filename at point.
;;; comint-dynamic-complete-variable Complete variable name at point.
;;; comint-input-ignoredups - boolean ...
;;; comint-last-input-match - string ...
;;; comint-dynamic-complete-functions - hook For the completion mechanism
+;;; comint-completion-fignore - list ...
;;; comint-get-old-input - function Hooks for specific
;;; comint-input-filter-functions - hook process-in-a-buffer
;;; comint-output-filter-functions - hook function modes.
This variable is buffer-local.")
+(defvar comint-password-prompt-regexp
+ "\\(^[Pp]assword\\|pass phrase\\):\\s *\\'"
+ "*Regexp matching prompts for passwords in the inferior process.
+This is used by `comint-watch-for-password-prompt'.")
+
;;; Here are the per-interpreter hooks.
(defvar comint-get-old-input (function comint-get-old-input-default)
"Function that returns old text in comint mode.
"Index of last matched history element.")
(defvar comint-matching-input-from-input-string ""
"Input previously used to match input history.")
+
+(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-input-autoexpand 'permanent-local t)
and addition is controlled by the variable `comint-input-ignoredups'.
Commands with no default key bindings include `send-invisible',
-`comint-dynamic-complete', `comint-list-dynamic-completions', and
+`comint-dynamic-complete', `comint-dynamic-list-filename-completions', and
`comint-magic-space'.
Input to, and output from, the subprocess can cause the window to scroll to
(kill-all-local-variables)
(setq major-mode 'comint-mode)
(setq mode-name "Comint")
- (setq mode-line-process '(": %s"))
+ (setq mode-line-process '(":%s"))
(use-local-map comint-mode-map)
(make-local-variable 'comint-last-input-start)
(setq comint-last-input-start (make-marker))
+ (set-marker comint-last-input-start (point-min))
(make-local-variable 'comint-last-input-end)
(setq comint-last-input-end (make-marker))
+ (set-marker comint-last-input-end (point-min))
(make-local-variable 'comint-last-output-start)
(setq comint-last-output-start (make-marker))
(make-local-variable 'comint-prompt-regexp) ; Don't set; default
(make-local-variable 'comint-input-ignoredups)
(make-local-variable 'comint-delimiter-argument-list)
(make-local-variable 'comint-dynamic-complete-functions)
+ (make-local-variable 'comint-completion-fignore)
(make-local-variable 'comint-get-old-input)
(make-local-variable 'comint-input-filter-functions)
(make-local-variable 'comint-input-filter)
(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-a" 'comint-bol)
+ (define-key comint-mode-map "\C-c\C-a" 'comint-bol)
(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)
(define-key comint-mode-map "\C-c\C-o" 'comint-kill-output)
(define-key comint-mode-map "\C-c\C-r" 'comint-show-output)
(define-key comint-mode-map "\C-c\C-e" 'comint-show-maximum-output)
- (define-key comint-mode-map "\C-c\C-h" 'comint-dynamic-list-input-ring)
+ (define-key comint-mode-map "\C-c\C-l" 'comint-dynamic-list-input-ring)
(define-key comint-mode-map "\C-c\C-n" 'comint-next-prompt)
(define-key comint-mode-map "\C-c\C-p" 'comint-previous-prompt)
(define-key comint-mode-map "\C-c\C-d" 'comint-send-eof)
(defun comint-check-proc (buffer)
"Return t if there is a living process associated w/buffer BUFFER.
-Living means the status is `run' or `stop'.
+Living means the status is `open', `run', or `stop'.
BUFFER can be either a buffer or the name of one."
(let ((proc (get-buffer-process buffer)))
- (and proc (memq (process-status proc) '(run stop)))))
+ (and proc (memq (process-status proc) '(open run stop)))))
;;; Note that this guy, unlike shell.el's make-shell, barfs if you pass it ()
;;; for the second argument (program).
(defun make-comint (name program &optional startfile &rest switches)
"Make a comint process NAME in a buffer, running PROGRAM.
The name of the buffer is made by surrounding NAME with `*'s.
-If there is already a running process in that buffer, it is not restarted.
-Optional third arg STARTFILE is the name of a file to send the contents of to
-the process. Any more args are arguments to PROGRAM."
+PROGRAM should be either a string denoting an executable program to create
+via `start-process', or a cons pair of the form (HOST . SERVICE) denoting a TCP
+connection to be opened via `open-network-stream'. If there is already a
+running process in that buffer, it is not restarted. Optional third arg
+STARTFILE is the name of a file to send the contents of to the process.
+
+If PROGRAM is a string, any more args are arguments to PROGRAM."
(let ((buffer (get-buffer-create (concat "*" name "*"))))
;; If no process, or nuked process, crank up a new one and put buffer in
;; comint mode. Otherwise, leave buffer and existing process alone.
(comint-exec buffer name program startfile switches)))
buffer))
+;;;###autoload
+(defun comint-run (program)
+ "Run PROGRAM in a comint buffer and switch to it.
+The buffer name is made by surrounding the file name of PROGRAM with `*'s.
+The file name is used to make a symbol name, such as `comint-sh-hook', and any
+hooks on this symbol are run in the buffer.
+See `make-comint' and `comint-exec'."
+ (interactive "sRun program: ")
+ (let ((name (file-name-nondirectory program)))
+ (switch-to-buffer (make-comint name program))
+ (run-hooks (intern-soft (concat "comint-" name "-hook")))))
+
(defun comint-exec (buffer name command startfile switches)
"Start up a process in buffer BUFFER for comint modes.
Blasts any old process running in the buffer. Doesn't set the buffer mode.
(let ((proc (get-buffer-process buffer))) ; Blast any old process.
(if proc (delete-process proc)))
;; Crank up a new process
- (let ((proc (comint-exec-1 name buffer command switches)))
+ (let ((proc
+ (if (consp command)
+ (open-network-stream name buffer (car command) (cdr command))
+ (comint-exec-1 name buffer command switches))))
(set-process-filter proc 'comint-output-filter)
(make-local-variable 'comint-ptyp)
(setq comint-ptyp process-connection-type) ; T if pty, NIL if pipe.
(defun comint-exec-1 (name buffer command switches)
(let ((process-environment
- (nconc (list "EMACS=t" "TERM=emacs"
- (format "TERMCAP=emacs:co#%d:tc=unknown" (frame-width)))
- process-environment)))
+ (nconc
+ ;; If using termcap, we specify `emacs' as the terminal type
+ ;; because that lets us specify a width.
+ ;; If using terminfo, we specify `unknown' because that is
+ ;; a defined terminal type. `emacs' is not a defined terminal type
+ ;; and there is no way for us to define it here.
+ ;; Some programs that use terminfo get very confused
+ ;; if TERM is not a valid terminal type.
+ (if (and (boundp 'system-uses-terminfo) system-uses-terminfo)
+ (list "EMACS=t" "TERM=unknown"
+ (format "COLUMNS=%d" (frame-width)))
+ (list "EMACS=t" "TERM=emacs"
+ (format "TERMCAP=emacs:co#%d:tc=unknown" (frame-width))))
+ process-environment)))
(apply 'start-process name buffer command switches)))
\f
;;; Input history processing in a buffer
(message "Cannot read history file %s"
comint-input-ring-file-name)))
(t
- (let ((history-buf (get-file-buffer comint-input-ring-file-name))
+ (let ((history-buf (get-buffer-create " *temp*"))
+ (file comint-input-ring-file-name)
+ (count 0)
(ring (make-ring comint-input-ring-size)))
- (save-excursion
- (set-buffer (or history-buf
- (find-file-noselect comint-input-ring-file-name)))
- ;; Save restriction in case file is already visited...
- ;; Watch for those date stamps in history files!
- (save-excursion
- (save-restriction
+ (unwind-protect
+ (save-excursion
+ (set-buffer history-buf)
(widen)
- (goto-char (point-min))
- (while (re-search-forward "^\\s *\\([^#].*\\)\\s *$" nil t)
+ (erase-buffer)
+ (insert-file-contents file)
+ ;; Save restriction in case file is already visited...
+ ;; Watch for those date stamps in history files!
+ (goto-char (point-max))
+ (while (and (< count comint-input-ring-size)
+ (re-search-backward "^[ \t]*\\([^#\n].*\\)[ \t]*$"
+ nil t))
(let ((history (buffer-substring (match-beginning 1)
(match-end 1))))
(if (or (null comint-input-ignoredups)
(ring-empty-p ring)
(not (string-equal (ring-ref ring 0) history)))
- (ring-insert ring history)))))
- ;; Kill buffer unless already visited.
- (if (null history-buf)
- (kill-buffer nil))))
+ (ring-insert-at-beginning ring history)))
+ (setq count (1+ count))))
+ (kill-buffer history-buf))
(setq comint-input-ring ring
comint-input-ring-index nil)))))
Returns t if successful."
(interactive)
(if (and comint-input-autoexpand
- (string-match "[!^]" (funcall comint-get-old-input)))
+ (string-match "[!^]" (funcall comint-get-old-input))
+ (save-excursion (beginning-of-line)
+ (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)
+ (comint-replace-by-expanded-history-before-point silent)
(/= previous-modified-tick (buffer-modified-tick)))))
-(defun comint-replace-by-expanded-history-before-point ()
+(defun comint-replace-by-expanded-history-before-point (silent)
"Expand directory stack reference before point.
See `comint-replace-by-expanded-history'. Returns t if successful."
(save-excursion
(comint-previous-matching-input-string-position
(concat pref (regexp-quote exp)) 1))))
(if (null pos)
- (or silent
- (progn (message "Not found")
- (goto-char (match-end 0))
- (ding)))
+ (progn
+ (goto-char (match-end 0))
+ (or silent
+ (progn (message "Not found")
+ (ding))))
(setq comint-input-ring-index pos)
(replace-match
(comint-args (ring-ref comint-input-ring pos)
Also, a run of one or more of a single character
in `comint-delimiter-argument-list' is a separate argument.
Argument 0 is the command name."
- (let ((arg "\\(\\(\"[^\"]*\"\\|\'[^\']*\'\\|\`[^\`]*\`\\)\\|\\S \\)+")
- (args ()) (pos 0) (str nil))
- ;; We build a list of all the args. Unnecessary, but more efficient, when
- ;; ranges of args are required, than picking out one by one and recursing.
- (while (string-match arg string pos)
- (setq pos (match-end 0)
- str (substring string (match-beginning 0) pos)
- ;; (match-end 2) is non-nil if we found quotes.
- args (if (match-end 2) (cons str args)
- (nconc (comint-delim-arg str) args))))
- (let ((n (or nth (1- (length args))))
- (m (if mth (1- (- (length args) mth)) 0)))
+ (let ((argpart "[^ \n\t\"'`]+\\|\\(\"[^\"]*\"\\|'[^']*'\\|`[^`]*`\\)")
+ (args ()) (pos 0)
+ (count 0)
+ beg str value quotes)
+ ;; Build a list of all the args until we have as many as we want.
+ (while (and (or (null mth) (<= count mth))
+ (string-match argpart string pos))
+ (if (and beg (= pos (match-beginning 0)))
+ ;; It's contiguous, part of the same arg.
+ (setq pos (match-end 0)
+ quotes (or quotes (match-beginning 1)))
+ ;; It's a new separate arg.
+ (if beg
+ ;; Put the previous arg, if there was one, onto ARGS.
+ (setq str (substring string beg pos)
+ args (if quotes (cons str args)
+ (nconc (comint-delim-arg str) args))
+ count (1+ count)))
+ (setq quotes (match-beginning 1))
+ (setq beg (match-beginning 0))
+ (setq pos (match-end 0))))
+ (if beg
+ (setq str (substring string beg pos)
+ args (if quotes (cons str args)
+ (nconc (comint-delim-arg str) args))
+ count (1+ count)))
+ (let ((n (or nth (1- count)))
+ (m (if mth (1- (- count mth)) 0)))
(mapconcat
(function (lambda (a) a)) (nthcdr n (nreverse (nthcdr m args))) " "))))
\f
(while functions
(funcall (car functions) (concat input "\n"))
(setq functions (cdr functions))))
- (funcall comint-input-sender proc input)
(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))
- ;; A kludge to prevent the delay between insert and process output
- ;; affecting the display. A case for a comint-send-input-hook?
- (if (eq (process-filter proc) 'comint-output-filter)
- (let ((functions comint-output-filter-functions))
- (while functions
- (funcall (car functions) (concat input "\n"))
- (setq functions (cdr functions)))))))))
+ (funcall comint-input-sender proc input)
+ (comint-output-filter proc "")))))
;; The purpose of using this filter for comint processes
;; is to keep comint-last-input-end from moving forward
nil t))
(set-buffer current))))
+(defun comint-strip-ctrl-m (&optional string)
+ "Strip trailing `^M' characters from the current output group.
+
+This function could be in the list `comint-output-filter-functions' or bound to
+a key."
+ (interactive)
+ (let ((pmark (process-mark (get-buffer-process (current-buffer)))))
+ (save-excursion
+ (goto-char
+ (if (interactive-p) comint-last-input-end comint-last-output-start))
+ (while (re-search-forward "\r+$" pmark t)
+ (replace-match "" t t)))))
+(defalias 'shell-strip-ctrl-m 'comint-strip-ctrl-m)
+
(defun comint-show-maximum-output ()
"Put the end of the buffer at the bottom of the window."
(interactive)
If prefix argument is given (\\[universal-argument]) the prompt is not skipped.
The prompt skip is done by skipping text matching the regular expression
-`comint-prompt-regexp', a buffer local variable.
-
-If you don't like this command, bind C-a to `beginning-of-line'
-in your hook, `comint-mode-hook'."
+`comint-prompt-regexp', a buffer local variable."
(interactive "P")
(beginning-of-line)
(if (null arg) (comint-skip-prompt)))
-;;; These two functions are for entering text you don't want echoed or
+;;; These three functions are for entering text you don't want echoed or
;;; saved -- typically passwords to ftp, telnet, or somesuch.
-;;; Just enter m-x send-invisible and type in your line.
+;;; Just enter m-x send-invisible and type in your line, or add
+;;; `comint-watch-for-password-prompt' to `comint-output-filter-functions'.
(defun comint-read-noecho (prompt &optional stars)
"Read a single line of text from user without echoing, and return it.
;; may clear quit-flag itself and return C-g. That would make
;; it impossible to quit this loop in a simple way, so
;; re-enable it here (for backward-compatibility the check for
- ;; quit-flag below would still be necessary, so this is seems
+ ;; quit-flag below would still be necessary, so this seems
;; like the simplest way to do things).
(setq quit-flag t
done t))
\\[view-lossage]."
(interactive "P") ; Defeat snooping via C-x esc
(let ((proc (get-buffer-process (current-buffer))))
- (if (not proc) (error "Current buffer has no process")
- (comint-send-string proc
- (if (stringp str) str
- (comint-read-noecho "Non-echoed text: " t)))
- (comint-send-string proc "\n"))))
-
+ (if (not proc)
+ (error "Current buffer has no process")
+ (comint-send-string
+ proc (if (stringp str) str (comint-read-noecho "Non-echoed text: " t)))
+ (comint-send-string proc "\n"))))
+
+(defun comint-watch-for-password-prompt (string)
+ "Prompt in the minibuffer for password and send without echoing.
+This function uses `send-invisible' to read and send a password to the buffer's
+process if STRING contains a password prompt defined by
+`comint-password-prompt-regexp'.
+
+This function could be in the list `comint-output-filter-functions'."
+ (if (string-match comint-password-prompt-regexp string)
+ (send-invisible nil)))
\f
;;; Low-level process communication
-(defvar comint-input-chunk-size 512
- "*Long inputs are sent to comint processes in chunks of this size.
-If your process is choking on big inputs, try lowering the value.")
-
-(defun comint-send-string (proc str)
- "Send PROCESS the contents of STRING as input.
-This is equivalent to `process-send-string', except that long input strings
-are broken up into chunks of size `comint-input-chunk-size'. Processes
-are given a chance to output between chunks. This can help prevent processes
-from hanging when you send them long inputs on some OS's."
- (let* ((len (length str))
- (i (min len comint-input-chunk-size)))
- (process-send-string proc (substring str 0 i))
- (while (< i len)
- (let ((next-i (+ i comint-input-chunk-size)))
- (accept-process-output)
- (sit-for 0)
- (process-send-string proc (substring str i (min len next-i)))
- (setq i next-i)))))
-
-(defun comint-send-region (proc start end)
- "Sends to PROC the region delimited by START and END.
-This is a replacement for `process-send-region' that tries to keep
-your process from hanging on long inputs. See `comint-send-string'."
- (comint-send-string proc (buffer-substring start end)))
+(defalias 'comint-send-string 'process-send-string)
+(defalias 'comint-send-region 'process-send-region)
\f
;;; Random input hackage
"Kill all output from interpreter since last input.
Does not delete the prompt."
(interactive)
- (let ((pmark (progn (goto-char
- (process-mark (get-buffer-process (current-buffer))))
- (beginning-of-line nil)
- (point-marker))))
- (kill-region comint-last-input-end pmark)
- (insert "*** output flushed ***\n")
- (comint-skip-prompt)
- (set-marker pmark (point))))
+ (let ((proc (get-buffer-process (current-buffer)))
+ (replacement nil))
+ (save-excursion
+ (let ((pmark (progn (goto-char (process-mark proc))
+ (beginning-of-line nil)
+ (point-marker))))
+ (delete-region comint-last-input-end pmark)
+ (comint-skip-prompt)
+ (setq replacement (concat "*** output flushed ***\n"
+ (buffer-substring pmark (point))))
+ (delete-region pmark (point))))
+ ;; Output message and put back prompt
+ (comint-output-filter proc replacement)))
(defun comint-show-output ()
"Display start of this batch of interpreter output at top of window.
-Also put cursor there if the current position is not visible."
+Sets mark to the value of point when this command is run."
(interactive)
(push-mark)
(let ((pos (point)))
A non-nil value is useful if `comint-completion-autolist' is non-nil too.")
+(defvar comint-completion-fignore nil
+ "*List of suffixes to be disregarded during file completion.
+This mirrors the optional behavior of bash and tcsh.
+
+Note that this applies to `comint-dynamic-complete-filename' only.")
+
(defvar comint-file-name-prefix ""
"Prefix prepended to absolute file names taken from process input.
This is used by comint's and shell's completion functions, and by shell's
adds completion characters to the end of the filename. A completions listing
may be shown in a help buffer if completion is ambiguous.
-Completion is dependent on the value of `comint-completion-addsuffix' and
-`comint-completion-recexact', and the timing of completions listing is
-dependent on the value of `comint-completion-autolist'.
+Completion is dependent on the value of `comint-completion-addsuffix',
+`comint-completion-recexact' and `comint-completion-fignore', and the timing of
+completions listing is dependent on the value of `comint-completion-autolist'.
Returns t if successful."
(interactive)
(if (comint-match-partial-filename)
- (prog2 (message "Completing file name...")
+ (prog2 (or (eq (selected-window) (minibuffer-window))
+ (message "Completing file name..."))
(comint-dynamic-complete-as-filename))))
"Dynamically complete at point as a filename.
See `comint-dynamic-complete-filename'. Returns t if successful."
(let* ((completion-ignore-case nil)
+ (completion-ignored-extensions comint-completion-fignore)
(success t)
- ;; For shell completion, treat all files as equally interesting.
- (completion-ignored-extensions nil)
(filename (or (comint-match-partial-filename) ""))
- (pathdir (file-name-directory filename))
- (pathnondir (file-name-nondirectory filename))
- (directory (if pathdir (comint-directory pathdir) default-directory))
- (completion (file-name-completion pathnondir directory)))
+ (pathdir (file-name-directory filename))
+ (pathnondir (file-name-nondirectory filename))
+ (directory (if pathdir (comint-directory pathdir) default-directory))
+ (completion (file-name-completion pathnondir directory))
+ (mini-flag (eq (selected-window) (minibuffer-window))))
(cond ((null completion)
(message "No completions of %s" filename)
(setq success nil))
((eq completion t) ; Means already completed "file".
(if comint-completion-addsuffix (insert " "))
- (message "Sole completion"))
+ (or mini-flag (message "Sole completion")))
((string-equal completion "") ; Means completion on "directory/".
(comint-dynamic-list-filename-completions))
(t ; Completion string returned.
(let ((file (concat (file-name-as-directory directory) completion)))
- (goto-char (match-end 0))
(insert (substring (directory-file-name completion)
(length pathnondir)))
(cond ((symbolp (file-name-completion completion directory))
;; We inserted a unique completion.
(if comint-completion-addsuffix
(insert (if (file-directory-p file) "/" " ")))
- (message "Completed"))
+ (or mini-flag (message "Completed")))
((and comint-completion-recexact comint-completion-addsuffix
(string-equal pathnondir completion)
(file-exists-p file))
;; It's not unique, but user wants shortest match.
(insert (if (file-directory-p file) "/" " "))
- (message "Completed shortest"))
+ (or mini-flag (message "Completed shortest")))
((or comint-completion-autolist
(string-equal pathnondir completion))
;; It's not unique, list possible completions.
(comint-dynamic-list-filename-completions))
(t
- (message "Partially completed"))))))
+ (or mini-flag (message "Partially completed")))))))
success))
"List in help buffer possible completions of the filename at point."
(interactive)
(let* ((completion-ignore-case nil)
- ;; For shell completion, treat all files as equally interesting.
- (completion-ignored-extensions nil)
(filename (or (comint-match-partial-filename) ""))
(pathdir (file-name-directory filename))
(pathnondir (file-name-nondirectory filename))
"List in help buffer sorted COMPLETIONS.
Typing SPC flushes the help buffer."
(let ((conf (current-window-configuration)))
- (with-output-to-temp-buffer " *Completions*"
+ (with-output-to-temp-buffer "*Completions*"
(display-completion-list (sort completions 'string-lessp)))
(message "Hit space to flush")
(let (key first)
(if (save-excursion
- (set-buffer (get-buffer " *Completions*"))
+ (set-buffer (get-buffer "*Completions*"))
(setq key (read-key-sequence nil)
first (aref key 0))
(and (consp first)
(eq (window-buffer (posn-window (event-start first)))
- (get-buffer " *Completions*"))
+ (get-buffer "*Completions*"))
(eq (key-binding key) 'mouse-choose-completion)))
;; If the user does mouse-choose-completion with the mouse,
;; execute the command, then delete the completion window.
(set-window-configuration conf))
(if (eq first ?\ )
(set-window-configuration conf)
- (setq unread-command-events (append key nil)))))))
+ (setq unread-command-events (listify-key-sequence key)))))))
\f
;;; Converting process modes to use comint mode
;;; ===========================================================================
;;;
;;; (defvar shell-mode-map '())
;;; (cond ((not shell-mode-map)
-;;; (setq shell-mode-map (full-copy-sparse-keymap comint-mode-map))
+;;; (setq shell-mode-map (copy-keymap comint-mode-map))
;;; (define-key shell-mode-map "\C-c\C-f" 'shell-forward-command)
;;; (define-key shell-mode-map "\C-c\C-b" 'shell-backward-command)
;;; (define-key shell-mode-map "\t" 'comint-dynamic-complete)