+ (message "%s" msg)))
+\f
+;; This was mostly copied from shell-resync-dirs.
+(defun shell-snarf-envar (var)
+ "Return as a string the shell's value of environment variable VAR."
+ (let* ((cmd (format "printenv '%s'\n" var))
+ (proc (get-buffer-process (current-buffer)))
+ (pmark (process-mark proc)))
+ (goto-char pmark)
+ (insert cmd)
+ (sit-for 0) ; force redisplay
+ (comint-send-string proc cmd)
+ (set-marker pmark (point))
+ (let ((pt (point))) ; wait for 1 line
+ ;; This extra newline prevents the user's pending input from spoofing us.
+ (insert "\n") (backward-char 1)
+ (while (not (looking-at ".+\n"))
+ (accept-process-output proc)
+ (goto-char pt)))
+ (goto-char pmark) (delete-char 1) ; remove the extra newline
+ (buffer-substring (match-beginning 0) (1- (match-end 0)))))
+
+(defun shell-copy-environment-variable (variable)
+ "Copy the environment variable VARIABLE from the subshell to Emacs.
+This command reads the value of the specified environment variable
+in the shell, and sets the same environment variable in Emacs
+\(what `getenv' in Emacs would return) to that value.
+That value will affect any new subprocesses that you subsequently start
+from Emacs."
+ (interactive (list (read-envvar-name "\
+Copy Shell environment variable to Emacs: ")))
+ (setenv variable (shell-snarf-envar variable)))
+\f
+(defun shell-forward-command (&optional arg)
+ "Move forward across ARG shell command(s). Does not cross lines.
+See `shell-command-regexp'."
+ (interactive "p")
+ (let ((limit (save-excursion (end-of-line nil) (point))))
+ (if (re-search-forward (concat shell-command-regexp "\\([;&|][\t ]*\\)+")
+ limit 'move arg)
+ (skip-syntax-backward " "))))
+
+
+(defun shell-backward-command (&optional arg)
+ "Move backward across ARG shell command(s). Does not cross lines.
+See `shell-command-regexp'."
+ (interactive "p")
+ (let ((limit (save-excursion (comint-bol nil) (point))))
+ (if (> limit (point))
+ (save-excursion (beginning-of-line) (setq limit (point))))
+ (skip-syntax-backward " " limit)
+ (if (re-search-backward
+ (format "[;&|]+[\t ]*\\(%s\\)" shell-command-regexp) limit 'move arg)
+ (progn (goto-char (match-beginning 1))
+ (skip-chars-forward ";&|")))))
+
+
+(defun shell-dynamic-complete-command ()
+ "Dynamically complete the command at point.
+This function is similar to `comint-dynamic-complete-filename', except that it
+searches `exec-path' (minus the trailing emacs library path) for completion
+candidates. Note that this may not be the same as the shell's idea of the
+path.
+
+Completion is dependent on the value of `shell-completion-execonly', plus
+those that effect file completion. See `shell-dynamic-complete-as-command'.
+
+Returns t if successful."
+ (interactive)
+ (let ((filename (comint-match-partial-filename)))
+ (if (and filename
+ (save-match-data (not (string-match "[~/]" filename)))
+ (eq (match-beginning 0)
+ (save-excursion (shell-backward-command 1) (point))))
+ (prog2 (message "Completing command name...")
+ (shell-dynamic-complete-as-command)))))
+
+
+(defun shell-dynamic-complete-as-command ()
+ "Dynamically complete at point as a command.
+See `shell-dynamic-complete-filename'. Returns t if successful."
+ (let* ((filename (or (comint-match-partial-filename) ""))
+ (pathnondir (file-name-nondirectory filename))
+ (paths (cdr (reverse exec-path)))
+ (cwd (file-name-as-directory (expand-file-name default-directory)))
+ (ignored-extensions
+ (and comint-completion-fignore
+ (mapconcat (function (lambda (x) (concat (regexp-quote x) "$")))
+ comint-completion-fignore "\\|")))
+ (path "") (comps-in-path ()) (file "") (filepath "") (completions ()))
+ ;; Go thru each path in the search path, finding completions.
+ (while paths
+ (setq path (file-name-as-directory (comint-directory (or (car paths) ".")))
+ comps-in-path (and (file-accessible-directory-p path)
+ (file-name-all-completions pathnondir path)))
+ ;; Go thru each completion found, to see whether it should be used.
+ (while comps-in-path
+ (setq file (car comps-in-path)
+ filepath (concat path file))
+ (if (and (not (member file completions))
+ (not (and ignored-extensions
+ (string-match ignored-extensions file)))
+ (or (string-equal path cwd)
+ (not (file-directory-p filepath)))
+ (or (null shell-completion-execonly)
+ (file-executable-p filepath)))
+ (setq completions (cons file completions)))
+ (setq comps-in-path (cdr comps-in-path)))
+ (setq paths (cdr paths)))
+ ;; OK, we've got a list of completions.
+ (let ((success (let ((comint-completion-addsuffix nil))
+ (comint-dynamic-simple-complete pathnondir completions))))
+ (if (and (memq success '(sole shortest)) comint-completion-addsuffix
+ (not (file-directory-p (comint-match-partial-filename))))
+ (insert " "))
+ success)))
+
+
+(defun shell-match-partial-variable ()
+ "Return the shell variable at point, or nil if none is found."
+ (save-excursion
+ (let ((limit (point)))
+ (if (re-search-backward "[^A-Za-z0-9_{}]" nil 'move)
+ (or (looking-at "\\$") (forward-char 1)))
+ ;; Anchor the search forwards.
+ (if (or (eolp) (looking-at "[^A-Za-z0-9_{}$]"))
+ nil
+ (re-search-forward "\\$?{?[A-Za-z0-9_]*}?" limit)
+ (buffer-substring (match-beginning 0) (match-end 0))))))
+
+
+(defun shell-dynamic-complete-environment-variable ()
+ "Dynamically complete the environment variable at point.
+Completes if after a variable, i.e., if it starts with a \"$\".
+See `shell-dynamic-complete-as-environment-variable'.
+
+This function is similar to `comint-dynamic-complete-filename', except that it
+searches `process-environment' for completion candidates. Note that this may
+not be the same as the interpreter's idea of variable names. The main problem
+with this type of completion is that `process-environment' is the environment
+which Emacs started with. Emacs does not track changes to the environment made
+by the interpreter. Perhaps it would be more accurate if this function was
+called `shell-dynamic-complete-process-environment-variable'.
+
+Returns non-nil if successful."
+ (interactive)
+ (let ((variable (shell-match-partial-variable)))
+ (if (and variable (string-match "^\\$" variable))
+ (prog2 (message "Completing variable name...")
+ (shell-dynamic-complete-as-environment-variable)))))
+
+
+(defun shell-dynamic-complete-as-environment-variable ()
+ "Dynamically complete at point as an environment variable.
+Used by `shell-dynamic-complete-environment-variable'.
+Uses `comint-dynamic-simple-complete'."
+ (let* ((var (or (shell-match-partial-variable) ""))
+ (variable (substring var (or (string-match "[^$({]\\|$" var) 0)))
+ (variables (mapcar (function (lambda (x)
+ (substring x 0 (string-match "=" x))))
+ process-environment))
+ (addsuffix comint-completion-addsuffix)
+ (comint-completion-addsuffix nil)
+ (success (comint-dynamic-simple-complete variable variables)))
+ (if (memq success '(sole shortest))
+ (let* ((var (shell-match-partial-variable))
+ (variable (substring var (string-match "[^$({]" var)))
+ (protection (cond ((string-match "{" var) "}")
+ ((string-match "(" var) ")")
+ (t "")))
+ (suffix (cond ((null addsuffix) "")
+ ((file-directory-p
+ (comint-directory (getenv variable))) "/")
+ (t " "))))
+ (insert protection suffix)))
+ success))
+
+
+(defun shell-replace-by-expanded-directory ()
+ "Expand directory stack reference before point.
+Directory stack references are of the form \"=digit\" or \"=-\".
+See `default-directory' and `shell-dirstack'.
+
+Returns t if successful."
+ (interactive)
+ (if (comint-match-partial-filename)
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (let ((stack (cons default-directory shell-dirstack))
+ (index (cond ((looking-at "=-/?")
+ (length shell-dirstack))
+ ((looking-at "=\\([0-9]+\\)")
+ (string-to-number
+ (buffer-substring
+ (match-beginning 1) (match-end 1)))))))
+ (cond ((null index)
+ nil)
+ ((>= index (length stack))
+ (error "Directory stack not that deep."))
+ (t
+ (replace-match (file-name-as-directory (nth index stack)) t t)
+ (message "Directory item: %d" index)
+ t))))))