+(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))))))
+\f