* lisp/shell.el: Use lexical-binding and std completion UI.

(shell-filter-ctrl-a-ctrl-b): Work as a preoutput filter.
(shell-mode): Put shell-filter-ctrl-a-ctrl-b on
comint-preoutput-filter-functions rather than on
comint-output-filter-functions.
(shell-command-completion, shell--command-completion-data)
(shell-filename-completion, shell-environment-variable-completion)
(shell-c-a-p-replace-by-expanded-directory): New functions.
(shell-dynamic-complete-functions, shell-dynamic-complete-command)
(shell-dynamic-complete-filename, shell-replace-by-expanded-directory)
(shell-dynamic-complete-environment-variable): Use them.
(shell-dynamic-complete-as-environment-variable)
(shell-dynamic-complete-as-command): Remove.
(shell-match-partial-variable): Match past point.
* lisp/comint.el: Clean up use of completion-at-point-functions.
(comint-completion-at-point): New function.
(comint-mode): Use it completion-at-point-functions.
(comint-dynamic-complete): Make it obsolete.
(comint-replace-by-expanded-history-before-point): Add dry-run arg.
(comint-c-a-p-replace-by-expanded-history): New function.
(comint-dynamic-complete-functions)
(comint-replace-by-expanded-history): Use it.
* lisp/minibuffer.el (completion-table-with-terminator): Allow dynamic
termination strings.  Try harder to avoid second try-completion.
(completion-in-region-mode-map): Disable bindings that don't work yet.
This commit is contained in:
Stefan Monnier 2011-04-20 19:31:06 -03:00
parent 2011338029
commit c0a193ea20
5 changed files with 203 additions and 120 deletions

View file

@ -370,6 +370,8 @@ $ESHELL nor variable `explicit-shell-file-name' is set.
* Changes in Specialized Modes and Packages in Emacs 24.1
** comint and modes derived from it use the generic completion code.
** The compile.el mode can be used without font-lock-mode.
`compilation-parse-errors-function' is now obsolete.

View file

@ -1,5 +1,31 @@
2011-04-20 Stefan Monnier <monnier@iro.umontreal.ca>
* shell.el: Use lexical-binding and std completion UI.
(shell-filter-ctrl-a-ctrl-b): Work as a preoutput filter.
(shell-mode): Put shell-filter-ctrl-a-ctrl-b on
comint-preoutput-filter-functions rather than on
comint-output-filter-functions.
(shell-command-completion, shell--command-completion-data)
(shell-filename-completion, shell-environment-variable-completion)
(shell-c-a-p-replace-by-expanded-directory): New functions.
(shell-dynamic-complete-functions, shell-dynamic-complete-command)
(shell-dynamic-complete-filename, shell-replace-by-expanded-directory)
(shell-dynamic-complete-environment-variable): Use them.
(shell-dynamic-complete-as-environment-variable)
(shell-dynamic-complete-as-command): Remove.
(shell-match-partial-variable): Match past point.
* comint.el: Clean up use of completion-at-point-functions.
(comint-completion-at-point): New function.
(comint-mode): Use it completion-at-point-functions.
(comint-dynamic-complete): Make it obsolete.
(comint-replace-by-expanded-history-before-point): Add dry-run arg.
(comint-c-a-p-replace-by-expanded-history): New function.
(comint-dynamic-complete-functions)
(comint-replace-by-expanded-history): Use it.
* minibuffer.el (completion-table-with-terminator): Allow dynamic
termination strings. Try harder to avoid second try-completion.
(completion-in-region-mode-map): Disable bindings that don't work yet.
* comint.el: Use lexical-binding. Require CL.
(comint-dynamic-complete-functions): Use comint-filename-completion.
(comint-completion-addsuffix): Tweak custom type.
@ -9,6 +35,7 @@
(comint-dynamic-complete-as-filename, comint-dynamic-complete-filename)
(comint-dynamic-list-filename-completions): Use them.
(comint-dynamic-simple-complete): Make obsolete.
* minibuffer.el (completion-in-region-mode):
Keep completion-in-region-mode--predicate global.
(completion-in-region--postch):

View file

@ -367,7 +367,7 @@ text matching `comint-prompt-regexp', depending on the value of
`comint-use-prompt-regexp'.")
(defvar comint-dynamic-complete-functions
'(comint-replace-by-expanded-history comint-filename-completion)
'(comint-c-a-p-replace-by-expanded-history comint-filename-completion)
"List of functions called to perform completion.
Works like `completion-at-point-functions'.
See also `comint-dynamic-complete'.
@ -493,7 +493,7 @@ executed once when the buffer is created."
(define-key map [menu-bar completion complete-file]
'("Complete File Name" . comint-dynamic-complete-filename))
(define-key map [menu-bar completion complete]
'("Complete Before Point" . comint-dynamic-complete))
'("Complete at Point" . completion-at-point))
;; Input history:
(define-key map [menu-bar inout]
(cons "In/Out" (make-sparse-keymap "In/Out")))
@ -683,6 +683,7 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
(setq font-lock-defaults '(nil t))
(add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
(add-hook 'isearch-mode-hook 'comint-history-isearch-setup nil t)
(add-hook 'completion-at-point-functions 'comint-completion-at-point nil t)
;; This behavior is not useful in comint buffers, and is annoying
(set (make-local-variable 'next-line-add-newlines) nil))
@ -1231,6 +1232,12 @@ See `comint-magic-space' and `comint-replace-by-expanded-history-before-point'.
Returns t if successful."
(interactive)
(let ((f (comint-c-a-p-replace-by-expanded-history silent start)))
(if f (funcall f))))
(defun comint-c-a-p-replace-by-expanded-history (&optional silent start)
"Expand input command history at point.
For use on `completion-at-point-functions'."
(if (and comint-input-autoexpand
(if comint-use-prompt-regexp
;; Use comint-prompt-regexp
@ -1240,20 +1247,28 @@ Returns t if successful."
;; Use input fields. User input that hasn't been entered
;; yet, at the end of the buffer, has a nil `field' property.
(and (null (get-char-property (point) 'field))
(string-match "!\\|^\\^" (field-string)))))
;; Looks like there might be history references in the command.
(let ((previous-modified-tick (buffer-modified-tick)))
(comint-replace-by-expanded-history-before-point silent start)
(/= previous-modified-tick (buffer-modified-tick)))))
(string-match "!\\|^\\^" (field-string))))
(catch 'dry-run
(comint-replace-by-expanded-history-before-point
silent start 'dry-run)))
(lambda ()
;; Looks like there might be history references in the command.
(let ((previous-modified-tick (buffer-modified-tick)))
(comint-replace-by-expanded-history-before-point silent start)
(/= previous-modified-tick (buffer-modified-tick))))))
(defun comint-replace-by-expanded-history-before-point (silent &optional start)
(defun comint-replace-by-expanded-history-before-point
(silent &optional start dry-run)
"Expand directory stack reference before point.
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."
than the logical beginning of line.
If DRY-RUN is non-nil, throw to DRY-RUN before performing any
actual side-effect."
(save-excursion
(let ((toend (- (line-end-position) (point)))
(start (or start (comint-line-beginning-position))))
@ -1274,10 +1289,12 @@ than the logical beginning of line."
(goto-char (1+ (point))))
((looking-at "![0-9]+\\($\\|[^-]\\)")
;; We cannot know the interpreter's idea of input line numbers.
(if dry-run (throw dry-run 'message))
(goto-char (match-end 0))
(message "Absolute reference cannot be expanded"))
((looking-at "!-\\([0-9]+\\)\\(:?[0-9^$*-]+\\)?")
;; Just a number of args from `number' lines backward.
(if dry-run (throw dry-run 'history))
(let ((number (1- (string-to-number
(buffer-substring (match-beginning 1)
(match-end 1))))))
@ -1293,6 +1310,7 @@ than the logical beginning of line."
(message "Relative reference exceeds input history size"))))
((or (looking-at "!!?:?\\([0-9^$*-]+\\)") (looking-at "!!"))
;; Just a number of args from the previous input line.
(if dry-run (throw dry-run 'expand))
(replace-match (comint-args (comint-previous-input-string 0)
(match-beginning 1) (match-end 1))
t t)
@ -1301,6 +1319,7 @@ than the logical beginning of line."
"!\\??\\({\\(.+\\)}\\|\\(\\sw+\\)\\)\\(:?[0-9^$*-]+\\)?")
;; Most recent input starting with or containing (possibly
;; protected) string, maybe just a number of args. Phew.
(if dry-run (throw dry-run 'expand))
(let* ((mb1 (match-beginning 1)) (me1 (match-end 1))
(mb2 (match-beginning 2)) (me2 (match-end 2))
(exp (buffer-substring (or mb2 mb1) (or me2 me1)))
@ -1322,6 +1341,7 @@ than the logical beginning of line."
(message "History item: %d" (1+ pos)))))
((looking-at "\\^\\([^^]+\\)\\^?\\([^^]*\\)\\^?")
;; Quick substitution on the previous input line.
(if dry-run (throw dry-run 'expand))
(let ((old (buffer-substring (match-beginning 1) (match-end 1)))
(new (buffer-substring (match-beginning 2) (match-end 2)))
(pos nil))
@ -1334,7 +1354,8 @@ than the logical beginning of line."
(replace-match new t t)
(message "History item: substituted"))))
(t
(forward-char 1)))))))
(forward-char 1)))))
nil))
(defun comint-magic-space (arg)
@ -1740,9 +1761,9 @@ Similarly for Soar, Scheme, etc."
(insert copy)
copy)))
(input (if (not (eq comint-input-autoexpand 'input))
;; Just whatever's already there
;; Just whatever's already there.
intxt
;; Expand and leave it visible in buffer
;; Expand and leave it visible in buffer.
(comint-replace-by-expanded-history t pmark)
(buffer-substring pmark (point))))
(history (if (not (eq comint-input-autoexpand 'history))
@ -2990,16 +3011,12 @@ Magic characters are those in `comint-file-name-quote-list'."
(setq i (+ 1 (match-beginning 0)))))
filename)))
(defun comint-completion-at-point ()
(run-hook-with-args-until-success 'comint-dynamic-complete-functions))
(defun comint-dynamic-complete ()
"Dynamically perform completion at point.
Calls the functions in `comint-dynamic-complete-functions' to perform
completion until a function returns non-nil, at which point completion is
assumed to have occurred."
(interactive)
(let ((completion-at-point-functions comint-dynamic-complete-functions))
(completion-at-point)))
(define-obsolete-function-alias
'comint-dynamic-complete
'completion-at-point "24.1")
(defun comint-dynamic-complete-filename ()
"Dynamically complete the filename at point.

View file

@ -247,7 +247,9 @@ TERMINATOR can also be a cons cell (TERMINATOR . TERMINATOR-REGEXP)
in which case TERMINATOR-REGEXP is a regular expression whose submatch
number 1 should match TERMINATOR. This is used when there is a need to
distinguish occurrences of the TERMINATOR strings which are really terminators
from others (e.g. escaped)."
from others (e.g. escaped). In this form, the car of TERMINATOR can also be,
instead of a string, a function that takes the completion and returns the
\"terminated\" string."
;; FIXME: This implementation is not right since it only adds the terminator
;; in try-completion, so any completion-style that builds the completion via
;; all-completions won't get the terminator, and selecting an entry in
@ -258,22 +260,28 @@ from others (e.g. escaped)."
(bounds (completion-boundaries string table pred suffix))
(terminator-regexp (if (consp terminator)
(cdr terminator) (regexp-quote terminator)))
(max (string-match terminator-regexp suffix)))
(max (and terminator-regexp
(string-match terminator-regexp suffix))))
(list* 'boundaries (car bounds)
(min (cdr bounds) (or max (length suffix))))))
((eq action nil)
(let ((comp (try-completion string table pred)))
(if (consp terminator) (setq terminator (car terminator)))
(if (eq comp t)
(concat string terminator)
(if (and (stringp comp)
;; FIXME: Try to avoid this second call, especially since
(if (functionp terminator)
(funcall terminator string)
(concat string terminator))
(if (and (stringp comp) (not (zerop (length comp)))
;; Try to avoid the second call to try-completion, since
;; it may be very inefficient (because `comp' made us
;; jump to a new boundary, so we complete in that
;; boundary with an empty start string).
;; completion-boundaries might help.
(let ((newbounds (completion-boundaries comp table pred "")))
(< (car newbounds) (length comp)))
(eq (try-completion comp table pred) t))
(concat comp terminator)
(if (functionp terminator)
(funcall terminator comp)
(concat comp terminator))
comp))))
((eq action t)
;; FIXME: We generally want the `try' and `all' behaviors to be
@ -1294,6 +1302,8 @@ Point needs to be somewhere between START and END."
(defvar completion-in-region-mode-map
(let ((map (make-sparse-keymap)))
;; FIXME: Only works if completion-in-region-mode was activated via
;; completion-at-point called directly.
(define-key map "?" 'completion-help-at-point)
(define-key map "\t" 'completion-at-point)
map)

View file

@ -1,4 +1,4 @@
;;; shell.el --- specialized comint.el for running the shell
;;; shell.el --- specialized comint.el for running the shell -*- lexical-binding: t -*-
;; Copyright (C) 1988, 1993-1997, 2000-2011 Free Software Foundation, Inc.
@ -79,7 +79,7 @@
;; Shell Mode Commands:
;; shell Fires up the shell process
;; tab comint-dynamic-complete Complete filename/command/history
;; tab completion-at-point Complete filename/command/history
;; m-? comint-dynamic-list-filename-completions
;; List completions in help buffer
;; m-c-f shell-forward-command Forward a shell command
@ -96,6 +96,7 @@
;;; Code:
(eval-when-compile (require 'cl))
(require 'comint)
;;; Customization and Buffer Variables
@ -181,12 +182,12 @@ shell buffer. The value may depend on the operating system or shell.
This is a fine thing to set in your `.emacs' file.")
(defvar shell-dynamic-complete-functions
'(comint-replace-by-expanded-history
shell-dynamic-complete-environment-variable
shell-dynamic-complete-command
shell-replace-by-expanded-directory
shell-dynamic-complete-filename
comint-dynamic-complete-filename)
'(comint-c-a-p-replace-by-expanded-history
shell-environment-variable-completion
shell-command-completion
shell-c-a-p-replace-by-expanded-directory
shell-filename-completion
comint-filename-completion)
"List of functions called to perform completion.
This variable is used to initialize `comint-dynamic-complete-functions' in the
shell buffer.
@ -312,7 +313,7 @@ This mirrors the optional behavior of tcsh (its autoexpand and histlit).
If the value is `input', then the expansion is seen on input.
If the value is `history', then the expansion is only when inserting
into the buffer's input ring. See also `comint-magic-space' and
`comint-dynamic-complete'.
`comint-dynamic-complete-functions'.
This variable supplies a default for `comint-input-autoexpand',
for Shell mode only."
@ -339,7 +340,7 @@ Thus, this does not include the shell's current directory.")
(let ((map (nconc (make-sparse-keymap) comint-mode-map)))
(define-key map "\C-c\C-f" 'shell-forward-command)
(define-key map "\C-c\C-b" 'shell-backward-command)
(define-key map "\t" 'comint-dynamic-complete)
(define-key map "\t" 'completion-at-point)
(define-key map (kbd "M-RET") 'shell-resync-dirs)
(define-key map "\M-?" 'comint-dynamic-list-filename-completions)
(define-key map [menu-bar completion]
@ -486,7 +487,7 @@ buffer."
(t "dirs")))
;; Bypass a bug in certain versions of bash.
(when (string-equal shell "bash")
(add-hook 'comint-output-filter-functions
(add-hook 'comint-preoutput-filter-functions
'shell-filter-ctrl-a-ctrl-b nil t)))
(when shell-dir-cookie-re
;; Watch for magic cookies in the output to track the current dir.
@ -494,7 +495,7 @@ buffer."
'shell-dir-cookie-watcher nil t))
(comint-read-input-ring t)))
(defun shell-filter-ctrl-a-ctrl-b (_string)
(defun shell-filter-ctrl-a-ctrl-b (string)
"Remove `^A' and `^B' characters from comint output.
Bash uses these characters as internal quoting characters in its
@ -504,15 +505,10 @@ started with the `--noediting' option and Select Graphic
Rendition (SGR) control sequences (formerly known as ANSI escape
sequences) are used to color the prompt.
This function can be put on `comint-output-filter-functions'.
The argument STRING is ignored."
(let ((pmark (process-mark (get-buffer-process (current-buffer)))))
(save-excursion
(goto-char (or (and (markerp comint-last-output-start)
(marker-position comint-last-output-start))
(point-min)))
(while (re-search-forward "[\C-a\C-b]" pmark t)
(replace-match "")))))
This function can be put on `comint-preoutput-filter-functions'."
(if (string-match "[\C-a\C-b]" string)
(replace-regexp-in-string "[\C-a\C-b]" "" string t t)
string))
(defun shell-write-history-on-exit (process event)
"Called when the shell process is stopped.
@ -1011,30 +1007,36 @@ 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'.
those that effect file completion.
Returns t if successful."
(interactive)
(let ((data (shell-command-completion)))
(if data
(prog2 (unless (window-minibuffer-p (selected-window))
(message "Completing command name..."))
(apply #'completion-in-region data)))))
(defun shell-command-completion ()
"Return the completion data for the command at point, if any."
(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 (unless (window-minibuffer-p (selected-window))
(message "Completing command name..."))
(shell-dynamic-complete-as-command)))))
(shell--command-completion-data))))
(defun shell-dynamic-complete-as-command ()
"Dynamically complete at point as a command.
See `shell-dynamic-complete-filename'. Returns t if successful."
(defun shell--command-completion-data ()
"Return the completion data for the command at point."
(let* ((filename (or (comint-match-partial-filename) ""))
(start (if (zerop (length filename)) (point) (match-beginning 0)))
(end (if (zerop (length filename)) (point) (match-end 0)))
(filenondir (file-name-nondirectory filename))
(path-dirs (cdr (reverse exec-path)))
(path-dirs (cdr (reverse exec-path))) ;FIXME: Why `cdr'?
(cwd (file-name-as-directory (expand-file-name default-directory)))
(ignored-extensions
(and comint-completion-fignore
(mapconcat (function (lambda (x) (concat (regexp-quote x) "$")))
(mapconcat (function (lambda (x) (concat (regexp-quote x) "\\'")))
comint-completion-fignore "\\|")))
(dir "") (comps-in-dir ())
(file "") (abs-file-name "") (completions ()))
@ -1058,18 +1060,31 @@ See `shell-dynamic-complete-filename'. Returns t if successful."
(setq comps-in-dir (cdr comps-in-dir)))
(setq path-dirs (cdr path-dirs)))
;; OK, we've got a list of completions.
(let ((success (let ((comint-completion-addsuffix nil))
(comint-dynamic-simple-complete filenondir completions))))
(if (and (memq success '(sole shortest)) comint-completion-addsuffix
(not (file-directory-p (comint-match-partial-filename))))
(insert " "))
success)))
(list
start end
(lambda (string pred action)
(completion-table-with-terminator
" " (lambda (string pred action)
(if (string-match "/" string)
(completion-file-name-table string pred action)
(complete-with-action action completions string pred)))
string pred action)))))
;; (defun shell-dynamic-complete-as-command ()
;; "Dynamically complete at point as a command.
;; See `shell-dynamic-complete-filename'. Returns t if successful."
;; (apply #'completion-in-region shell--command-completion-data))
(defun shell-dynamic-complete-filename ()
"Dynamically complete the filename at point.
This completes only if point is at a suitable position for a
filename argument."
(interactive)
(let ((data (shell-filename-completion)))
(if data (apply #'completion-in-region data))))
(defun shell-filename-completion ()
"Return the completion data for file name at point, if any."
(let ((opoint (point))
(beg (comint-line-beginning-position)))
(when (save-excursion
@ -1077,24 +1092,21 @@ filename argument."
(match-end 0)
beg))
(re-search-forward "[^ \t][ \t]" opoint t))
(comint-dynamic-complete-as-filename))))
(comint-filename-completion))))
(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))))))
(if (re-search-backward "[^A-Za-z0-9_{(]" nil 'move)
(or (looking-at "\\$") (forward-char 1)))
(if (or (eolp) (looking-at "[^A-Za-z0-9_{($]"))
nil
(looking-at "\\$?[{(]?[A-Za-z0-9_]*[})]?")
(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
@ -1106,39 +1118,70 @@ 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))
(let ((data (shell-environment-variable-completion)))
(if data
(prog2 (unless (window-minibuffer-p (selected-window))
(message "Completing variable name..."))
(shell-dynamic-complete-as-environment-variable)))))
(apply #'completion-in-region data)))))
(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-environment-variable-completion ()
"Completion data for an environment variable at point, if any."
(let* ((var (shell-match-partial-variable))
(end (match-end 0)))
(when (and (not (zerop (length var))) (eq (aref var 0) ?$))
(let* ((start
(save-excursion
(goto-char (match-beginning 0))
(looking-at "\\$?[({]*")
(match-end 0)))
(variables (mapcar (lambda (x)
(substring x 0 (string-match "=" x)))
process-environment))
(suffix (case (char-before start) (?\{ "}") (?\( ")") (t ""))))
(list
start end
(apply-partially
#'completion-table-with-terminator
(cons (lambda (comp)
(concat comp
suffix
(if (file-directory-p
(comint-directory (getenv comp)))
"/")))
"\\`a\\`")
variables))))))
(defun shell-c-a-p-replace-by-expanded-directory ()
"Expand directory stack reference before point.
For use on `completion-at-point-functions'."
(when (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)))))))
(when index
(let ((start (match-beginning 0))
(end (match-end 0))
(replacement (file-name-as-directory (nth index stack))))
(lambda ()
(cond
((>= index (length stack))
(error "Directory stack not that deep"))
(t
(save-excursion
(goto-char start)
(insert replacement)
(delete-char (- end start)))
(message "Directory item: %d" index)
t)))))))))
(defun shell-replace-by-expanded-directory ()
"Expand directory stack reference before point.
Directory stack references are of the form \"=digit\" or \"=-\".
@ -1146,24 +1189,8 @@ 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))))))
(let ((f (shell-c-a-p-replace-by-expanded-directory)))
(if f (funcall f))))
(provide 'shell)