aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2011-04-20 19:31:06 -0300
committerStefan Monnier2011-04-20 19:31:06 -0300
commitc0a193ea2017fbaa6fb3e64a07125878656da156 (patch)
tree52ecaae3b27b33e9de36b354cbc2d17e2334f411
parent201133802956936332f1c4ce04eac42dfd1cf1c6 (diff)
downloademacs-c0a193ea2017fbaa6fb3e64a07125878656da156.tar.gz
emacs-c0a193ea2017fbaa6fb3e64a07125878656da156.zip
* 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.
-rw-r--r--etc/NEWS2
-rw-r--r--lisp/ChangeLog27
-rw-r--r--lisp/comint.el63
-rw-r--r--lisp/minibuffer.el24
-rw-r--r--lisp/shell.el217
5 files changed, 208 insertions, 125 deletions
diff --git a/etc/NEWS b/etc/NEWS
index bc85b3223ed..aed90764fa1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -370,6 +370,8 @@ $ESHELL nor variable `explicit-shell-file-name' is set.
370 370
371* Changes in Specialized Modes and Packages in Emacs 24.1 371* Changes in Specialized Modes and Packages in Emacs 24.1
372 372
373** comint and modes derived from it use the generic completion code.
374
373** The compile.el mode can be used without font-lock-mode. 375** The compile.el mode can be used without font-lock-mode.
374`compilation-parse-errors-function' is now obsolete. 376`compilation-parse-errors-function' is now obsolete.
375 377
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 214376b817c..70bb631df9e 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,31 @@
12011-04-20 Stefan Monnier <monnier@iro.umontreal.ca> 12011-04-20 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * shell.el: Use lexical-binding and std completion UI.
4 (shell-filter-ctrl-a-ctrl-b): Work as a preoutput filter.
5 (shell-mode): Put shell-filter-ctrl-a-ctrl-b on
6 comint-preoutput-filter-functions rather than on
7 comint-output-filter-functions.
8 (shell-command-completion, shell--command-completion-data)
9 (shell-filename-completion, shell-environment-variable-completion)
10 (shell-c-a-p-replace-by-expanded-directory): New functions.
11 (shell-dynamic-complete-functions, shell-dynamic-complete-command)
12 (shell-dynamic-complete-filename, shell-replace-by-expanded-directory)
13 (shell-dynamic-complete-environment-variable): Use them.
14 (shell-dynamic-complete-as-environment-variable)
15 (shell-dynamic-complete-as-command): Remove.
16 (shell-match-partial-variable): Match past point.
17 * comint.el: Clean up use of completion-at-point-functions.
18 (comint-completion-at-point): New function.
19 (comint-mode): Use it completion-at-point-functions.
20 (comint-dynamic-complete): Make it obsolete.
21 (comint-replace-by-expanded-history-before-point): Add dry-run arg.
22 (comint-c-a-p-replace-by-expanded-history): New function.
23 (comint-dynamic-complete-functions)
24 (comint-replace-by-expanded-history): Use it.
25 * minibuffer.el (completion-table-with-terminator): Allow dynamic
26 termination strings. Try harder to avoid second try-completion.
27 (completion-in-region-mode-map): Disable bindings that don't work yet.
28
3 * comint.el: Use lexical-binding. Require CL. 29 * comint.el: Use lexical-binding. Require CL.
4 (comint-dynamic-complete-functions): Use comint-filename-completion. 30 (comint-dynamic-complete-functions): Use comint-filename-completion.
5 (comint-completion-addsuffix): Tweak custom type. 31 (comint-completion-addsuffix): Tweak custom type.
@@ -9,6 +35,7 @@
9 (comint-dynamic-complete-as-filename, comint-dynamic-complete-filename) 35 (comint-dynamic-complete-as-filename, comint-dynamic-complete-filename)
10 (comint-dynamic-list-filename-completions): Use them. 36 (comint-dynamic-list-filename-completions): Use them.
11 (comint-dynamic-simple-complete): Make obsolete. 37 (comint-dynamic-simple-complete): Make obsolete.
38
12 * minibuffer.el (completion-in-region-mode): 39 * minibuffer.el (completion-in-region-mode):
13 Keep completion-in-region-mode--predicate global. 40 Keep completion-in-region-mode--predicate global.
14 (completion-in-region--postch): 41 (completion-in-region--postch):
diff --git a/lisp/comint.el b/lisp/comint.el
index 735770a8908..8608c0d31e9 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -367,7 +367,7 @@ text matching `comint-prompt-regexp', depending on the value of
367`comint-use-prompt-regexp'.") 367`comint-use-prompt-regexp'.")
368 368
369(defvar comint-dynamic-complete-functions 369(defvar comint-dynamic-complete-functions
370 '(comint-replace-by-expanded-history comint-filename-completion) 370 '(comint-c-a-p-replace-by-expanded-history comint-filename-completion)
371 "List of functions called to perform completion. 371 "List of functions called to perform completion.
372Works like `completion-at-point-functions'. 372Works like `completion-at-point-functions'.
373See also `comint-dynamic-complete'. 373See also `comint-dynamic-complete'.
@@ -493,7 +493,7 @@ executed once when the buffer is created."
493 (define-key map [menu-bar completion complete-file] 493 (define-key map [menu-bar completion complete-file]
494 '("Complete File Name" . comint-dynamic-complete-filename)) 494 '("Complete File Name" . comint-dynamic-complete-filename))
495 (define-key map [menu-bar completion complete] 495 (define-key map [menu-bar completion complete]
496 '("Complete Before Point" . comint-dynamic-complete)) 496 '("Complete at Point" . completion-at-point))
497 ;; Input history: 497 ;; Input history:
498 (define-key map [menu-bar inout] 498 (define-key map [menu-bar inout]
499 (cons "In/Out" (make-sparse-keymap "In/Out"))) 499 (cons "In/Out" (make-sparse-keymap "In/Out")))
@@ -683,6 +683,7 @@ Entry to this mode runs the hooks on `comint-mode-hook'."
683 (setq font-lock-defaults '(nil t)) 683 (setq font-lock-defaults '(nil t))
684 (add-hook 'change-major-mode-hook 'font-lock-defontify nil t) 684 (add-hook 'change-major-mode-hook 'font-lock-defontify nil t)
685 (add-hook 'isearch-mode-hook 'comint-history-isearch-setup nil t) 685 (add-hook 'isearch-mode-hook 'comint-history-isearch-setup nil t)
686 (add-hook 'completion-at-point-functions 'comint-completion-at-point nil t)
686 ;; This behavior is not useful in comint buffers, and is annoying 687 ;; This behavior is not useful in comint buffers, and is annoying
687 (set (make-local-variable 'next-line-add-newlines) nil)) 688 (set (make-local-variable 'next-line-add-newlines) nil))
688 689
@@ -1231,6 +1232,12 @@ See `comint-magic-space' and `comint-replace-by-expanded-history-before-point'.
1231 1232
1232Returns t if successful." 1233Returns t if successful."
1233 (interactive) 1234 (interactive)
1235 (let ((f (comint-c-a-p-replace-by-expanded-history silent start)))
1236 (if f (funcall f))))
1237
1238(defun comint-c-a-p-replace-by-expanded-history (&optional silent start)
1239 "Expand input command history at point.
1240For use on `completion-at-point-functions'."
1234 (if (and comint-input-autoexpand 1241 (if (and comint-input-autoexpand
1235 (if comint-use-prompt-regexp 1242 (if comint-use-prompt-regexp
1236 ;; Use comint-prompt-regexp 1243 ;; Use comint-prompt-regexp
@@ -1240,20 +1247,28 @@ Returns t if successful."
1240 ;; Use input fields. User input that hasn't been entered 1247 ;; Use input fields. User input that hasn't been entered
1241 ;; yet, at the end of the buffer, has a nil `field' property. 1248 ;; yet, at the end of the buffer, has a nil `field' property.
1242 (and (null (get-char-property (point) 'field)) 1249 (and (null (get-char-property (point) 'field))
1243 (string-match "!\\|^\\^" (field-string))))) 1250 (string-match "!\\|^\\^" (field-string))))
1244 ;; Looks like there might be history references in the command. 1251 (catch 'dry-run
1245 (let ((previous-modified-tick (buffer-modified-tick))) 1252 (comint-replace-by-expanded-history-before-point
1246 (comint-replace-by-expanded-history-before-point silent start) 1253 silent start 'dry-run)))
1247 (/= previous-modified-tick (buffer-modified-tick))))) 1254 (lambda ()
1248 1255 ;; Looks like there might be history references in the command.
1249 1256 (let ((previous-modified-tick (buffer-modified-tick)))
1250(defun comint-replace-by-expanded-history-before-point (silent &optional start) 1257 (comint-replace-by-expanded-history-before-point silent start)
1258 (/= previous-modified-tick (buffer-modified-tick))))))
1259
1260
1261(defun comint-replace-by-expanded-history-before-point
1262 (silent &optional start dry-run)
1251 "Expand directory stack reference before point. 1263 "Expand directory stack reference before point.
1252See `comint-replace-by-expanded-history'. Returns t if successful. 1264See `comint-replace-by-expanded-history'. Returns t if successful.
1253 1265
1254If the optional argument START is non-nil, that specifies the 1266If the optional argument START is non-nil, that specifies the
1255start of the text to scan for history references, rather 1267start of the text to scan for history references, rather
1256than the logical beginning of line." 1268than the logical beginning of line.
1269
1270If DRY-RUN is non-nil, throw to DRY-RUN before performing any
1271actual side-effect."
1257 (save-excursion 1272 (save-excursion
1258 (let ((toend (- (line-end-position) (point))) 1273 (let ((toend (- (line-end-position) (point)))
1259 (start (or start (comint-line-beginning-position)))) 1274 (start (or start (comint-line-beginning-position))))
@@ -1274,10 +1289,12 @@ than the logical beginning of line."
1274 (goto-char (1+ (point)))) 1289 (goto-char (1+ (point))))
1275 ((looking-at "![0-9]+\\($\\|[^-]\\)") 1290 ((looking-at "![0-9]+\\($\\|[^-]\\)")
1276 ;; We cannot know the interpreter's idea of input line numbers. 1291 ;; We cannot know the interpreter's idea of input line numbers.
1292 (if dry-run (throw dry-run 'message))
1277 (goto-char (match-end 0)) 1293 (goto-char (match-end 0))
1278 (message "Absolute reference cannot be expanded")) 1294 (message "Absolute reference cannot be expanded"))
1279 ((looking-at "!-\\([0-9]+\\)\\(:?[0-9^$*-]+\\)?") 1295 ((looking-at "!-\\([0-9]+\\)\\(:?[0-9^$*-]+\\)?")
1280 ;; Just a number of args from `number' lines backward. 1296 ;; Just a number of args from `number' lines backward.
1297 (if dry-run (throw dry-run 'history))
1281 (let ((number (1- (string-to-number 1298 (let ((number (1- (string-to-number
1282 (buffer-substring (match-beginning 1) 1299 (buffer-substring (match-beginning 1)
1283 (match-end 1)))))) 1300 (match-end 1))))))
@@ -1293,6 +1310,7 @@ than the logical beginning of line."
1293 (message "Relative reference exceeds input history size")))) 1310 (message "Relative reference exceeds input history size"))))
1294 ((or (looking-at "!!?:?\\([0-9^$*-]+\\)") (looking-at "!!")) 1311 ((or (looking-at "!!?:?\\([0-9^$*-]+\\)") (looking-at "!!"))
1295 ;; Just a number of args from the previous input line. 1312 ;; Just a number of args from the previous input line.
1313 (if dry-run (throw dry-run 'expand))
1296 (replace-match (comint-args (comint-previous-input-string 0) 1314 (replace-match (comint-args (comint-previous-input-string 0)
1297 (match-beginning 1) (match-end 1)) 1315 (match-beginning 1) (match-end 1))
1298 t t) 1316 t t)
@@ -1301,6 +1319,7 @@ than the logical beginning of line."
1301 "!\\??\\({\\(.+\\)}\\|\\(\\sw+\\)\\)\\(:?[0-9^$*-]+\\)?") 1319 "!\\??\\({\\(.+\\)}\\|\\(\\sw+\\)\\)\\(:?[0-9^$*-]+\\)?")
1302 ;; Most recent input starting with or containing (possibly 1320 ;; Most recent input starting with or containing (possibly
1303 ;; protected) string, maybe just a number of args. Phew. 1321 ;; protected) string, maybe just a number of args. Phew.
1322 (if dry-run (throw dry-run 'expand))
1304 (let* ((mb1 (match-beginning 1)) (me1 (match-end 1)) 1323 (let* ((mb1 (match-beginning 1)) (me1 (match-end 1))
1305 (mb2 (match-beginning 2)) (me2 (match-end 2)) 1324 (mb2 (match-beginning 2)) (me2 (match-end 2))
1306 (exp (buffer-substring (or mb2 mb1) (or me2 me1))) 1325 (exp (buffer-substring (or mb2 mb1) (or me2 me1)))
@@ -1322,6 +1341,7 @@ than the logical beginning of line."
1322 (message "History item: %d" (1+ pos))))) 1341 (message "History item: %d" (1+ pos)))))
1323 ((looking-at "\\^\\([^^]+\\)\\^?\\([^^]*\\)\\^?") 1342 ((looking-at "\\^\\([^^]+\\)\\^?\\([^^]*\\)\\^?")
1324 ;; Quick substitution on the previous input line. 1343 ;; Quick substitution on the previous input line.
1344 (if dry-run (throw dry-run 'expand))
1325 (let ((old (buffer-substring (match-beginning 1) (match-end 1))) 1345 (let ((old (buffer-substring (match-beginning 1) (match-end 1)))
1326 (new (buffer-substring (match-beginning 2) (match-end 2))) 1346 (new (buffer-substring (match-beginning 2) (match-end 2)))
1327 (pos nil)) 1347 (pos nil))
@@ -1334,7 +1354,8 @@ than the logical beginning of line."
1334 (replace-match new t t) 1354 (replace-match new t t)
1335 (message "History item: substituted")))) 1355 (message "History item: substituted"))))
1336 (t 1356 (t
1337 (forward-char 1))))))) 1357 (forward-char 1)))))
1358 nil))
1338 1359
1339 1360
1340(defun comint-magic-space (arg) 1361(defun comint-magic-space (arg)
@@ -1740,9 +1761,9 @@ Similarly for Soar, Scheme, etc."
1740 (insert copy) 1761 (insert copy)
1741 copy))) 1762 copy)))
1742 (input (if (not (eq comint-input-autoexpand 'input)) 1763 (input (if (not (eq comint-input-autoexpand 'input))
1743 ;; Just whatever's already there 1764 ;; Just whatever's already there.
1744 intxt 1765 intxt
1745 ;; Expand and leave it visible in buffer 1766 ;; Expand and leave it visible in buffer.
1746 (comint-replace-by-expanded-history t pmark) 1767 (comint-replace-by-expanded-history t pmark)
1747 (buffer-substring pmark (point)))) 1768 (buffer-substring pmark (point))))
1748 (history (if (not (eq comint-input-autoexpand 'history)) 1769 (history (if (not (eq comint-input-autoexpand 'history))
@@ -2990,16 +3011,12 @@ Magic characters are those in `comint-file-name-quote-list'."
2990 (setq i (+ 1 (match-beginning 0))))) 3011 (setq i (+ 1 (match-beginning 0)))))
2991 filename))) 3012 filename)))
2992 3013
3014(defun comint-completion-at-point ()
3015 (run-hook-with-args-until-success 'comint-dynamic-complete-functions))
2993 3016
2994(defun comint-dynamic-complete () 3017(define-obsolete-function-alias
2995 "Dynamically perform completion at point. 3018 'comint-dynamic-complete
2996Calls the functions in `comint-dynamic-complete-functions' to perform 3019 'completion-at-point "24.1")
2997completion until a function returns non-nil, at which point completion is
2998assumed to have occurred."
2999 (interactive)
3000 (let ((completion-at-point-functions comint-dynamic-complete-functions))
3001 (completion-at-point)))
3002
3003 3020
3004(defun comint-dynamic-complete-filename () 3021(defun comint-dynamic-complete-filename ()
3005 "Dynamically complete the filename at point. 3022 "Dynamically complete the filename at point.
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 0adf2a1d8b8..e012c324012 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -247,7 +247,9 @@ TERMINATOR can also be a cons cell (TERMINATOR . TERMINATOR-REGEXP)
247in which case TERMINATOR-REGEXP is a regular expression whose submatch 247in which case TERMINATOR-REGEXP is a regular expression whose submatch
248number 1 should match TERMINATOR. This is used when there is a need to 248number 1 should match TERMINATOR. This is used when there is a need to
249distinguish occurrences of the TERMINATOR strings which are really terminators 249distinguish occurrences of the TERMINATOR strings which are really terminators
250from others (e.g. escaped)." 250from others (e.g. escaped). In this form, the car of TERMINATOR can also be,
251instead of a string, a function that takes the completion and returns the
252\"terminated\" string."
251 ;; FIXME: This implementation is not right since it only adds the terminator 253 ;; FIXME: This implementation is not right since it only adds the terminator
252 ;; in try-completion, so any completion-style that builds the completion via 254 ;; in try-completion, so any completion-style that builds the completion via
253 ;; all-completions won't get the terminator, and selecting an entry in 255 ;; all-completions won't get the terminator, and selecting an entry in
@@ -258,22 +260,28 @@ from others (e.g. escaped)."
258 (bounds (completion-boundaries string table pred suffix)) 260 (bounds (completion-boundaries string table pred suffix))
259 (terminator-regexp (if (consp terminator) 261 (terminator-regexp (if (consp terminator)
260 (cdr terminator) (regexp-quote terminator))) 262 (cdr terminator) (regexp-quote terminator)))
261 (max (string-match terminator-regexp suffix))) 263 (max (and terminator-regexp
264 (string-match terminator-regexp suffix))))
262 (list* 'boundaries (car bounds) 265 (list* 'boundaries (car bounds)
263 (min (cdr bounds) (or max (length suffix)))))) 266 (min (cdr bounds) (or max (length suffix))))))
264 ((eq action nil) 267 ((eq action nil)
265 (let ((comp (try-completion string table pred))) 268 (let ((comp (try-completion string table pred)))
266 (if (consp terminator) (setq terminator (car terminator))) 269 (if (consp terminator) (setq terminator (car terminator)))
267 (if (eq comp t) 270 (if (eq comp t)
268 (concat string terminator) 271 (if (functionp terminator)
269 (if (and (stringp comp) 272 (funcall terminator string)
270 ;; FIXME: Try to avoid this second call, especially since 273 (concat string terminator))
274 (if (and (stringp comp) (not (zerop (length comp)))
275 ;; Try to avoid the second call to try-completion, since
271 ;; it may be very inefficient (because `comp' made us 276 ;; it may be very inefficient (because `comp' made us
272 ;; jump to a new boundary, so we complete in that 277 ;; jump to a new boundary, so we complete in that
273 ;; boundary with an empty start string). 278 ;; boundary with an empty start string).
274 ;; completion-boundaries might help. 279 (let ((newbounds (completion-boundaries comp table pred "")))
280 (< (car newbounds) (length comp)))
275 (eq (try-completion comp table pred) t)) 281 (eq (try-completion comp table pred) t))
276 (concat comp terminator) 282 (if (functionp terminator)
283 (funcall terminator comp)
284 (concat comp terminator))
277 comp)))) 285 comp))))
278 ((eq action t) 286 ((eq action t)
279 ;; FIXME: We generally want the `try' and `all' behaviors to be 287 ;; FIXME: We generally want the `try' and `all' behaviors to be
@@ -1294,6 +1302,8 @@ Point needs to be somewhere between START and END."
1294 1302
1295(defvar completion-in-region-mode-map 1303(defvar completion-in-region-mode-map
1296 (let ((map (make-sparse-keymap))) 1304 (let ((map (make-sparse-keymap)))
1305 ;; FIXME: Only works if completion-in-region-mode was activated via
1306 ;; completion-at-point called directly.
1297 (define-key map "?" 'completion-help-at-point) 1307 (define-key map "?" 'completion-help-at-point)
1298 (define-key map "\t" 'completion-at-point) 1308 (define-key map "\t" 'completion-at-point)
1299 map) 1309 map)
diff --git a/lisp/shell.el b/lisp/shell.el
index 57187b6d7f9..d6bc685618c 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -1,4 +1,4 @@
1;;; shell.el --- specialized comint.el for running the shell 1;;; shell.el --- specialized comint.el for running the shell -*- lexical-binding: t -*-
2 2
3;; Copyright (C) 1988, 1993-1997, 2000-2011 Free Software Foundation, Inc. 3;; Copyright (C) 1988, 1993-1997, 2000-2011 Free Software Foundation, Inc.
4 4
@@ -79,7 +79,7 @@
79 79
80;; Shell Mode Commands: 80;; Shell Mode Commands:
81;; shell Fires up the shell process 81;; shell Fires up the shell process
82;; tab comint-dynamic-complete Complete filename/command/history 82;; tab completion-at-point Complete filename/command/history
83;; m-? comint-dynamic-list-filename-completions 83;; m-? comint-dynamic-list-filename-completions
84;; List completions in help buffer 84;; List completions in help buffer
85;; m-c-f shell-forward-command Forward a shell command 85;; m-c-f shell-forward-command Forward a shell command
@@ -96,6 +96,7 @@
96 96
97;;; Code: 97;;; Code:
98 98
99(eval-when-compile (require 'cl))
99(require 'comint) 100(require 'comint)
100 101
101;;; Customization and Buffer Variables 102;;; Customization and Buffer Variables
@@ -181,12 +182,12 @@ shell buffer. The value may depend on the operating system or shell.
181This is a fine thing to set in your `.emacs' file.") 182This is a fine thing to set in your `.emacs' file.")
182 183
183(defvar shell-dynamic-complete-functions 184(defvar shell-dynamic-complete-functions
184 '(comint-replace-by-expanded-history 185 '(comint-c-a-p-replace-by-expanded-history
185 shell-dynamic-complete-environment-variable 186 shell-environment-variable-completion
186 shell-dynamic-complete-command 187 shell-command-completion
187 shell-replace-by-expanded-directory 188 shell-c-a-p-replace-by-expanded-directory
188 shell-dynamic-complete-filename 189 shell-filename-completion
189 comint-dynamic-complete-filename) 190 comint-filename-completion)
190 "List of functions called to perform completion. 191 "List of functions called to perform completion.
191This variable is used to initialize `comint-dynamic-complete-functions' in the 192This variable is used to initialize `comint-dynamic-complete-functions' in the
192shell buffer. 193shell buffer.
@@ -312,7 +313,7 @@ This mirrors the optional behavior of tcsh (its autoexpand and histlit).
312If the value is `input', then the expansion is seen on input. 313If the value is `input', then the expansion is seen on input.
313If the value is `history', then the expansion is only when inserting 314If the value is `history', then the expansion is only when inserting
314into the buffer's input ring. See also `comint-magic-space' and 315into the buffer's input ring. See also `comint-magic-space' and
315`comint-dynamic-complete'. 316`comint-dynamic-complete-functions'.
316 317
317This variable supplies a default for `comint-input-autoexpand', 318This variable supplies a default for `comint-input-autoexpand',
318for Shell mode only." 319for Shell mode only."
@@ -339,7 +340,7 @@ Thus, this does not include the shell's current directory.")
339 (let ((map (nconc (make-sparse-keymap) comint-mode-map))) 340 (let ((map (nconc (make-sparse-keymap) comint-mode-map)))
340 (define-key map "\C-c\C-f" 'shell-forward-command) 341 (define-key map "\C-c\C-f" 'shell-forward-command)
341 (define-key map "\C-c\C-b" 'shell-backward-command) 342 (define-key map "\C-c\C-b" 'shell-backward-command)
342 (define-key map "\t" 'comint-dynamic-complete) 343 (define-key map "\t" 'completion-at-point)
343 (define-key map (kbd "M-RET") 'shell-resync-dirs) 344 (define-key map (kbd "M-RET") 'shell-resync-dirs)
344 (define-key map "\M-?" 'comint-dynamic-list-filename-completions) 345 (define-key map "\M-?" 'comint-dynamic-list-filename-completions)
345 (define-key map [menu-bar completion] 346 (define-key map [menu-bar completion]
@@ -486,7 +487,7 @@ buffer."
486 (t "dirs"))) 487 (t "dirs")))
487 ;; Bypass a bug in certain versions of bash. 488 ;; Bypass a bug in certain versions of bash.
488 (when (string-equal shell "bash") 489 (when (string-equal shell "bash")
489 (add-hook 'comint-output-filter-functions 490 (add-hook 'comint-preoutput-filter-functions
490 'shell-filter-ctrl-a-ctrl-b nil t))) 491 'shell-filter-ctrl-a-ctrl-b nil t)))
491 (when shell-dir-cookie-re 492 (when shell-dir-cookie-re
492 ;; Watch for magic cookies in the output to track the current dir. 493 ;; Watch for magic cookies in the output to track the current dir.
@@ -494,7 +495,7 @@ buffer."
494 'shell-dir-cookie-watcher nil t)) 495 'shell-dir-cookie-watcher nil t))
495 (comint-read-input-ring t))) 496 (comint-read-input-ring t)))
496 497
497(defun shell-filter-ctrl-a-ctrl-b (_string) 498(defun shell-filter-ctrl-a-ctrl-b (string)
498 "Remove `^A' and `^B' characters from comint output. 499 "Remove `^A' and `^B' characters from comint output.
499 500
500Bash uses these characters as internal quoting characters in its 501Bash uses these characters as internal quoting characters in its
@@ -504,15 +505,10 @@ started with the `--noediting' option and Select Graphic
504Rendition (SGR) control sequences (formerly known as ANSI escape 505Rendition (SGR) control sequences (formerly known as ANSI escape
505sequences) are used to color the prompt. 506sequences) are used to color the prompt.
506 507
507This function can be put on `comint-output-filter-functions'. 508This function can be put on `comint-preoutput-filter-functions'."
508The argument STRING is ignored." 509 (if (string-match "[\C-a\C-b]" string)
509 (let ((pmark (process-mark (get-buffer-process (current-buffer))))) 510 (replace-regexp-in-string "[\C-a\C-b]" "" string t t)
510 (save-excursion 511 string))
511 (goto-char (or (and (markerp comint-last-output-start)
512 (marker-position comint-last-output-start))
513 (point-min)))
514 (while (re-search-forward "[\C-a\C-b]" pmark t)
515 (replace-match "")))))
516 512
517(defun shell-write-history-on-exit (process event) 513(defun shell-write-history-on-exit (process event)
518 "Called when the shell process is stopped. 514 "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
1011path. 1007path.
1012 1008
1013Completion is dependent on the value of `shell-completion-execonly', plus 1009Completion is dependent on the value of `shell-completion-execonly', plus
1014those that effect file completion. See `shell-dynamic-complete-as-command'. 1010those that effect file completion.
1015 1011
1016Returns t if successful." 1012Returns t if successful."
1017 (interactive) 1013 (interactive)
1014 (let ((data (shell-command-completion)))
1015 (if data
1016 (prog2 (unless (window-minibuffer-p (selected-window))
1017 (message "Completing command name..."))
1018 (apply #'completion-in-region data)))))
1019
1020(defun shell-command-completion ()
1021 "Return the completion data for the command at point, if any."
1018 (let ((filename (comint-match-partial-filename))) 1022 (let ((filename (comint-match-partial-filename)))
1019 (if (and filename 1023 (if (and filename
1020 (save-match-data (not (string-match "[~/]" filename))) 1024 (save-match-data (not (string-match "[~/]" filename)))
1021 (eq (match-beginning 0) 1025 (eq (match-beginning 0)
1022 (save-excursion (shell-backward-command 1) (point)))) 1026 (save-excursion (shell-backward-command 1) (point))))
1023 (prog2 (unless (window-minibuffer-p (selected-window)) 1027 (shell--command-completion-data))))
1024 (message "Completing command name..."))
1025 (shell-dynamic-complete-as-command)))))
1026 1028
1027 1029(defun shell--command-completion-data ()
1028(defun shell-dynamic-complete-as-command () 1030 "Return the completion data for the command at point."
1029 "Dynamically complete at point as a command.
1030See `shell-dynamic-complete-filename'. Returns t if successful."
1031 (let* ((filename (or (comint-match-partial-filename) "")) 1031 (let* ((filename (or (comint-match-partial-filename) ""))
1032 (start (if (zerop (length filename)) (point) (match-beginning 0)))
1033 (end (if (zerop (length filename)) (point) (match-end 0)))
1032 (filenondir (file-name-nondirectory filename)) 1034 (filenondir (file-name-nondirectory filename))
1033 (path-dirs (cdr (reverse exec-path))) 1035 (path-dirs (cdr (reverse exec-path))) ;FIXME: Why `cdr'?
1034 (cwd (file-name-as-directory (expand-file-name default-directory))) 1036 (cwd (file-name-as-directory (expand-file-name default-directory)))
1035 (ignored-extensions 1037 (ignored-extensions
1036 (and comint-completion-fignore 1038 (and comint-completion-fignore
1037 (mapconcat (function (lambda (x) (concat (regexp-quote x) "$"))) 1039 (mapconcat (function (lambda (x) (concat (regexp-quote x) "\\'")))
1038 comint-completion-fignore "\\|"))) 1040 comint-completion-fignore "\\|")))
1039 (dir "") (comps-in-dir ()) 1041 (dir "") (comps-in-dir ())
1040 (file "") (abs-file-name "") (completions ())) 1042 (file "") (abs-file-name "") (completions ()))
@@ -1058,18 +1060,31 @@ See `shell-dynamic-complete-filename'. Returns t if successful."
1058 (setq comps-in-dir (cdr comps-in-dir))) 1060 (setq comps-in-dir (cdr comps-in-dir)))
1059 (setq path-dirs (cdr path-dirs))) 1061 (setq path-dirs (cdr path-dirs)))
1060 ;; OK, we've got a list of completions. 1062 ;; OK, we've got a list of completions.
1061 (let ((success (let ((comint-completion-addsuffix nil)) 1063 (list
1062 (comint-dynamic-simple-complete filenondir completions)))) 1064 start end
1063 (if (and (memq success '(sole shortest)) comint-completion-addsuffix 1065 (lambda (string pred action)
1064 (not (file-directory-p (comint-match-partial-filename)))) 1066 (completion-table-with-terminator
1065 (insert " ")) 1067 " " (lambda (string pred action)
1066 success))) 1068 (if (string-match "/" string)
1069 (completion-file-name-table string pred action)
1070 (complete-with-action action completions string pred)))
1071 string pred action)))))
1072
1073;; (defun shell-dynamic-complete-as-command ()
1074;; "Dynamically complete at point as a command.
1075;; See `shell-dynamic-complete-filename'. Returns t if successful."
1076;; (apply #'completion-in-region shell--command-completion-data))
1067 1077
1068(defun shell-dynamic-complete-filename () 1078(defun shell-dynamic-complete-filename ()
1069 "Dynamically complete the filename at point. 1079 "Dynamically complete the filename at point.
1070This completes only if point is at a suitable position for a 1080This completes only if point is at a suitable position for a
1071filename argument." 1081filename argument."
1072 (interactive) 1082 (interactive)
1083 (let ((data (shell-filename-completion)))
1084 (if data (apply #'completion-in-region data))))
1085
1086(defun shell-filename-completion ()
1087 "Return the completion data for file name at point, if any."
1073 (let ((opoint (point)) 1088 (let ((opoint (point))
1074 (beg (comint-line-beginning-position))) 1089 (beg (comint-line-beginning-position)))
1075 (when (save-excursion 1090 (when (save-excursion
@@ -1077,24 +1092,21 @@ filename argument."
1077 (match-end 0) 1092 (match-end 0)
1078 beg)) 1093 beg))
1079 (re-search-forward "[^ \t][ \t]" opoint t)) 1094 (re-search-forward "[^ \t][ \t]" opoint t))
1080 (comint-dynamic-complete-as-filename)))) 1095 (comint-filename-completion))))
1081 1096
1082(defun shell-match-partial-variable () 1097(defun shell-match-partial-variable ()
1083 "Return the shell variable at point, or nil if none is found." 1098 "Return the shell variable at point, or nil if none is found."
1084 (save-excursion 1099 (save-excursion
1085 (let ((limit (point))) 1100 (if (re-search-backward "[^A-Za-z0-9_{(]" nil 'move)
1086 (if (re-search-backward "[^A-Za-z0-9_{}]" nil 'move) 1101 (or (looking-at "\\$") (forward-char 1)))
1087 (or (looking-at "\\$") (forward-char 1))) 1102 (if (or (eolp) (looking-at "[^A-Za-z0-9_{($]"))
1088 ;; Anchor the search forwards. 1103 nil
1089 (if (or (eolp) (looking-at "[^A-Za-z0-9_{}$]")) 1104 (looking-at "\\$?[{(]?[A-Za-z0-9_]*[})]?")
1090 nil 1105 (buffer-substring (match-beginning 0) (match-end 0)))))
1091 (re-search-forward "\\$?{?[A-Za-z0-9_]*}?" limit)
1092 (buffer-substring (match-beginning 0) (match-end 0))))))
1093 1106
1094(defun shell-dynamic-complete-environment-variable () 1107(defun shell-dynamic-complete-environment-variable ()
1095 "Dynamically complete the environment variable at point. 1108 "Dynamically complete the environment variable at point.
1096Completes if after a variable, i.e., if it starts with a \"$\". 1109Completes if after a variable, i.e., if it starts with a \"$\".
1097See `shell-dynamic-complete-as-environment-variable'.
1098 1110
1099This function is similar to `comint-dynamic-complete-filename', except that it 1111This function is similar to `comint-dynamic-complete-filename', except that it
1100searches `process-environment' for completion candidates. Note that this may 1112searches `process-environment' for completion candidates. Note that this may
@@ -1106,38 +1118,69 @@ called `shell-dynamic-complete-process-environment-variable'.
1106 1118
1107Returns non-nil if successful." 1119Returns non-nil if successful."
1108 (interactive) 1120 (interactive)
1109 (let ((variable (shell-match-partial-variable))) 1121 (let ((data (shell-environment-variable-completion)))
1110 (if (and variable (string-match "^\\$" variable)) 1122 (if data
1111 (prog2 (unless (window-minibuffer-p (selected-window)) 1123 (prog2 (unless (window-minibuffer-p (selected-window))
1112 (message "Completing variable name...")) 1124 (message "Completing variable name..."))
1113 (shell-dynamic-complete-as-environment-variable))))) 1125 (apply #'completion-in-region data)))))
1114 1126
1115 1127
1116(defun shell-dynamic-complete-as-environment-variable () 1128(defun shell-environment-variable-completion ()
1117 "Dynamically complete at point as an environment variable. 1129 "Completion data for an environment variable at point, if any."
1118Used by `shell-dynamic-complete-environment-variable'. 1130 (let* ((var (shell-match-partial-variable))
1119Uses `comint-dynamic-simple-complete'." 1131 (end (match-end 0)))
1120 (let* ((var (or (shell-match-partial-variable) "")) 1132 (when (and (not (zerop (length var))) (eq (aref var 0) ?$))
1121 (variable (substring var (or (string-match "[^$({]\\|$" var) 0))) 1133 (let* ((start
1122 (variables (mapcar (function (lambda (x) 1134 (save-excursion
1123 (substring x 0 (string-match "=" x)))) 1135 (goto-char (match-beginning 0))
1124 process-environment)) 1136 (looking-at "\\$?[({]*")
1125 (addsuffix comint-completion-addsuffix) 1137 (match-end 0)))
1126 (comint-completion-addsuffix nil) 1138 (variables (mapcar (lambda (x)
1127 (success (comint-dynamic-simple-complete variable variables))) 1139 (substring x 0 (string-match "=" x)))
1128 (if (memq success '(sole shortest)) 1140 process-environment))
1129 (let* ((var (shell-match-partial-variable)) 1141 (suffix (case (char-before start) (?\{ "}") (?\( ")") (t ""))))
1130 (variable (substring var (string-match "[^$({]" var))) 1142 (list
1131 (protection (cond ((string-match "{" var) "}") 1143 start end
1132 ((string-match "(" var) ")") 1144 (apply-partially
1133 (t ""))) 1145 #'completion-table-with-terminator
1134 (suffix (cond ((null addsuffix) "") 1146 (cons (lambda (comp)
1135 ((file-directory-p 1147 (concat comp
1136 (comint-directory (getenv variable))) "/") 1148 suffix
1137 (t " ")))) 1149 (if (file-directory-p
1138 (insert protection suffix))) 1150 (comint-directory (getenv comp)))
1139 success)) 1151 "/")))
1140 1152 "\\`a\\`")
1153 variables))))))
1154
1155
1156(defun shell-c-a-p-replace-by-expanded-directory ()
1157 "Expand directory stack reference before point.
1158For use on `completion-at-point-functions'."
1159 (when (comint-match-partial-filename)
1160 (save-excursion
1161 (goto-char (match-beginning 0))
1162 (let ((stack (cons default-directory shell-dirstack))
1163 (index (cond ((looking-at "=-/?")
1164 (length shell-dirstack))
1165 ((looking-at "=\\([0-9]+\\)/?")
1166 (string-to-number
1167 (buffer-substring
1168 (match-beginning 1) (match-end 1)))))))
1169 (when index
1170 (let ((start (match-beginning 0))
1171 (end (match-end 0))
1172 (replacement (file-name-as-directory (nth index stack))))
1173 (lambda ()
1174 (cond
1175 ((>= index (length stack))
1176 (error "Directory stack not that deep"))
1177 (t
1178 (save-excursion
1179 (goto-char start)
1180 (insert replacement)
1181 (delete-char (- end start)))
1182 (message "Directory item: %d" index)
1183 t)))))))))
1141 1184
1142(defun shell-replace-by-expanded-directory () 1185(defun shell-replace-by-expanded-directory ()
1143 "Expand directory stack reference before point. 1186 "Expand directory stack reference before point.
@@ -1146,24 +1189,8 @@ See `default-directory' and `shell-dirstack'.
1146 1189
1147Returns t if successful." 1190Returns t if successful."
1148 (interactive) 1191 (interactive)
1149 (if (comint-match-partial-filename) 1192 (let ((f (shell-c-a-p-replace-by-expanded-directory)))
1150 (save-excursion 1193 (if f (funcall f))))
1151 (goto-char (match-beginning 0))
1152 (let ((stack (cons default-directory shell-dirstack))
1153 (index (cond ((looking-at "=-/?")
1154 (length shell-dirstack))
1155 ((looking-at "=\\([0-9]+\\)/?")
1156 (string-to-number
1157 (buffer-substring
1158 (match-beginning 1) (match-end 1)))))))
1159 (cond ((null index)
1160 nil)
1161 ((>= index (length stack))
1162 (error "Directory stack not that deep"))
1163 (t
1164 (replace-match (file-name-as-directory (nth index stack)) t t)
1165 (message "Directory item: %d" index)
1166 t))))))
1167 1194
1168(provide 'shell) 1195(provide 'shell)
1169 1196