(eshell-var): Fix typo in docstring.
[bpt/emacs.git] / lisp / eshell / em-cmpl.el
CommitLineData
60370d40 1;;; em-cmpl.el --- completion using the TAB key
affbf647 2
faadfb0a 3;; Copyright (C) 1999, 2000 Free Software Foundation
affbf647 4
7de5b421
GM
5;; Author: John Wiegley <johnw@gnu.org>
6
affbf647
GM
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation; either version 2, or (at your option)
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs; see the file COPYING. If not, write to the
21;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22;; Boston, MA 02111-1307, USA.
23
24(provide 'em-cmpl)
25
26(eval-when-compile (require 'esh-maint))
d3f92b4b 27(require 'esh-util)
affbf647
GM
28
29(defgroup eshell-cmpl nil
30 "This module provides a programmable completion function bound to
31the TAB key, which allows for completing command names, file names,
32variable names, arguments, etc."
33 :tag "Argument completion"
34 :group 'eshell-module)
35
36;;; Commentary:
37
38;; Eshell, by using the pcomplete package, provides a full
39;; programmable completion facility that is comparable to shells like
40;; tcsh or zsh.
41;;
42;; Completions are context-sensitive, which means that pressing <TAB>
43;; after the command 'rmdir' will result in a list of directories,
44;; while doing so after 'rm' will result in a list of all file
45;; entries.
46;;
47;; Many builtin completion rules are provided, for commands such as
48;; `cvs', or RedHat's `rpm' utility. Adding new completion rules is
49;; no more difficult than writing a plain Lisp functions, and they can
50;; be debugged, profiled, and compiled using exactly the same
51;; facilities (since in fact, they *are* just Lisp functions). See
52;; the definition of the function `pcomplete/make' for an example of
53;; how to write a completion function.
54;;
55;; The completion facility is very easy to use. Just press TAB. If
56;; there are a large number of possible completions, a buffer will
2696c102 57;; appear showing a list of them. Completions may be selected from
affbf647
GM
58;; that buffer using the mouse. If no completion is selected, and the
59;; user starts doing something else, the display buffer will
60;; automatically disappear.
61;;
62;; If the list of possible completions is very small, Eshell will
63;; "cycle" through them, selecting a different entry each time <TAB>
64;; is pressed. <S-TAB> may be used to cycle in the opposite
65;; direction.
66;;
67;; Glob patterns can also be cycled. For example, entering 'echo
68;; x*<tab>' will cycle through all the filenames beginning with 'x'.
69;; This is done because the glob list is treated as though it were a
70;; list of possible completions. Pressing <C-c SPC> will insert all
71;; of the matching glob patterns at point.
72;;
73;; If a Lisp form is being entered, <TAB> will complete the Lisp
74;; symbol name, in exactly the same way that <M-TAB> does in Emacs
75;; Lisp mode.
76;;
77;; The list of possible completions can be viewed at any point by
78;; pressing <M-?>.
79;;
80;; Finally, context-related help can be accessed by pressing <C-c i>.
81;; This only works well if the completion function has provided Eshell
82;; with sufficient pointers to locate the relevant help text.
83
84;;; User Variables:
85
86(defcustom eshell-cmpl-load-hook '(eshell-cmpl-initialize)
87 "*A list of functions to run when `eshell-cmpl' is loaded."
88 :type 'hook
89 :group 'eshell-cmpl)
90
91(defcustom eshell-show-lisp-completions nil
92 "*If non-nil, include Lisp functions in the command completion list.
93If this variable is nil, Lisp completion can still be done in command
94position by using M-TAB instead of TAB."
95 :type 'boolean
96 :group 'eshell-cmpl)
97
98(defcustom eshell-show-lisp-alternatives t
99 "*If non-nil, and no other completions found, show Lisp functions.
100Setting this variable means nothing if `eshell-show-lisp-completions'
101is non-nil."
102 :type 'boolean
103 :group 'eshell-cmpl)
104
105(defcustom eshell-no-completion-during-jobs t
106 "*If non-nil, don't allow completion while a process is running."
107 :type 'boolean
108 :group 'eshell-cmpl)
109
110(defcustom eshell-command-completions-alist
111 '(("acroread" . "\\.pdf\\'")
112 ("xpdf" . "\\.pdf\\'")
113 ("ar" . "\\.[ao]\\'")
114 ("gcc" . "\\.[Cc]\\([Cc]\\|[Pp][Pp]\\)?\\'")
115 ("g++" . "\\.[Cc]\\([Cc]\\|[Pp][Pp]\\)?\\'")
116 ("cc" . "\\.[Cc]\\([Cc]\\|[Pp][Pp]\\)?\\'")
117 ("CC" . "\\.[Cc]\\([Cc]\\|[Pp][Pp]\\)?\\'")
118 ("acc" . "\\.[Cc]\\([Cc]\\|[Pp][Pp]\\)?\\'")
119 ("bcc" . "\\.[Cc]\\([Cc]\\|[Pp][Pp]\\)?\\'")
d7da23c9
JW
120 ("readelf" . "\\(\\`[^.]*\\|\\.\\([ao]\\|so\\)\\)\\'")
121 ("objdump" . "\\(\\`[^.]*\\|\\.\\([ao]\\|so\\)\\)\\'")
122 ("nm" . "\\(\\`[^.]*\\|\\.\\([ao]\\|so\\)\\)\\'")
affbf647
GM
123 ("gdb" . "\\`\\([^.]*\\|a\\.out\\)\\'")
124 ("dbx" . "\\`\\([^.]*\\|a\\.out\\)\\'")
125 ("sdb" . "\\`\\([^.]*\\|a\\.out\\)\\'")
126 ("adb" . "\\`\\([^.]*\\|a\\.out\\)\\'"))
127 "*An alist that defines simple argument type correlations.
128This is provided for common commands, as a simplistic alternative
129to writing a completion function."
130 :type '(repeat (cons string regexp))
131 :group 'eshell-cmpl)
132
133(defcustom eshell-cmpl-file-ignore "~\\'"
134 (documentation-property 'pcomplete-file-ignore
135 'variable-documentation)
136 :type (get 'pcomplete-file-ignore 'custom-type)
137 :group 'eshell-cmpl)
138
6b0e3e4d 139(defcustom eshell-cmpl-dir-ignore "\\`\\(\\.\\.?\\|CVS\\)/\\'"
affbf647
GM
140 (documentation-property 'pcomplete-dir-ignore
141 'variable-documentation)
142 :type (get 'pcomplete-dir-ignore 'custom-type)
143 :group 'eshell-cmpl)
144
70a06174 145(defcustom eshell-cmpl-ignore-case (eshell-under-windows-p)
affbf647
GM
146 (documentation-property 'pcomplete-ignore-case
147 'variable-documentation)
148 :type (get 'pcomplete-ignore-case 'custom-type)
149 :group 'eshell-cmpl)
150
151(defcustom eshell-cmpl-autolist nil
152 (documentation-property 'pcomplete-autolist
153 'variable-documentation)
154 :type (get 'pcomplete-autolist 'custom-type)
155 :group 'eshell-cmpl)
156
6b0e3e4d 157(defcustom eshell-cmpl-suffix-list (list ?/ ?:)
affbf647
GM
158 (documentation-property 'pcomplete-suffix-list
159 'variable-documentation)
160 :type (get 'pcomplete-suffix-list 'custom-type)
161 :group 'pcomplete)
162
163(defcustom eshell-cmpl-recexact nil
164 (documentation-property 'pcomplete-recexact
165 'variable-documentation)
166 :type (get 'pcomplete-recexact 'custom-type)
167 :group 'eshell-cmpl)
168
169(defcustom eshell-cmpl-man-function 'man
170 (documentation-property 'pcomplete-man-function
171 'variable-documentation)
172 :type (get 'pcomplete-man-function 'custom-type)
173 :group 'eshell-cmpl)
174
175(defcustom eshell-cmpl-compare-entry-function 'file-newer-than-file-p
176 (documentation-property 'pcomplete-compare-entry-function
177 'variable-documentation)
178 :type (get 'pcomplete-compare-entry-function 'custom-type)
179 :group 'eshell-cmpl)
180
181(defcustom eshell-cmpl-expand-before-complete nil
182 (documentation-property 'pcomplete-expand-before-complete
183 'variable-documentation)
184 :type (get 'pcomplete-expand-before-complete 'custom-type)
185 :group 'eshell-cmpl)
186
187(defcustom eshell-cmpl-cycle-completions t
188 (documentation-property 'pcomplete-cycle-completions
189 'variable-documentation)
190 :type (get 'pcomplete-cycle-completions 'custom-type)
191 :group 'eshell-cmpl)
192
193(defcustom eshell-cmpl-cycle-cutoff-length 5
194 (documentation-property 'pcomplete-cycle-cutoff-length
195 'variable-documentation)
196 :type (get 'pcomplete-cycle-cutoff-length 'custom-type)
197 :group 'eshell-cmpl)
198
199(defcustom eshell-cmpl-restore-window-delay 1
200 (documentation-property 'pcomplete-restore-window-delay
201 'variable-documentation)
202 :type (get 'pcomplete-restore-window-delay 'custom-type)
203 :group 'eshell-cmpl)
204
205(defcustom eshell-command-completion-function
206 (function
207 (lambda ()
208 (pcomplete-here (eshell-complete-commands-list))))
209 (documentation-property 'pcomplete-command-completion-function
210 'variable-documentation)
211 :type (get 'pcomplete-command-completion-function 'custom-type)
212 :group 'eshell-cmpl)
213
214(defcustom eshell-cmpl-command-name-function
215 'eshell-completion-command-name
216 (documentation-property 'pcomplete-command-name-function
217 'variable-documentation)
218 :type (get 'pcomplete-command-name-function 'custom-type)
219 :group 'eshell-cmpl)
220
221(defcustom eshell-default-completion-function
222 (function
223 (lambda ()
224 (while (pcomplete-here
225 (pcomplete-dirs-or-entries
226 (cdr (assoc (funcall eshell-cmpl-command-name-function)
227 eshell-command-completions-alist)))))))
228 (documentation-property 'pcomplete-default-completion-function
229 'variable-documentation)
230 :type (get 'pcomplete-default-completion-function 'custom-type)
ca7aae91
JW
231 :group 'eshell-cmpl)
232
233(defcustom eshell-cmpl-use-paring t
234 (documentation-property 'pcomplete-use-paring 'variable-documentation)
235 :type (get 'pcomplete-use-paring 'custom-type)
236 :group 'eshell-cmpl)
affbf647
GM
237
238;;; Functions:
239
240(defun eshell-cmpl-initialize ()
241 "Initialize the completions module."
242 (unless (fboundp 'pcomplete)
243 (load "pcmpl-auto" t t))
244 (set (make-local-variable 'pcomplete-command-completion-function)
245 eshell-command-completion-function)
246 (set (make-local-variable 'pcomplete-command-name-function)
247 eshell-cmpl-command-name-function)
248 (set (make-local-variable 'pcomplete-default-completion-function)
249 eshell-default-completion-function)
250 (set (make-local-variable 'pcomplete-parse-arguments-function)
251 'eshell-complete-parse-arguments)
252 (set (make-local-variable 'pcomplete-file-ignore)
253 eshell-cmpl-file-ignore)
254 (set (make-local-variable 'pcomplete-dir-ignore)
255 eshell-cmpl-dir-ignore)
256 (set (make-local-variable 'pcomplete-ignore-case)
257 eshell-cmpl-ignore-case)
258 (set (make-local-variable 'pcomplete-autolist)
259 eshell-cmpl-autolist)
260 (set (make-local-variable 'pcomplete-suffix-list)
261 eshell-cmpl-suffix-list)
262 (set (make-local-variable 'pcomplete-recexact)
263 eshell-cmpl-recexact)
264 (set (make-local-variable 'pcomplete-man-function)
265 eshell-cmpl-man-function)
266 (set (make-local-variable 'pcomplete-compare-entry-function)
267 eshell-cmpl-compare-entry-function)
268 (set (make-local-variable 'pcomplete-expand-before-complete)
269 eshell-cmpl-expand-before-complete)
270 (set (make-local-variable 'pcomplete-cycle-completions)
271 eshell-cmpl-cycle-completions)
272 (set (make-local-variable 'pcomplete-cycle-cutoff-length)
273 eshell-cmpl-cycle-cutoff-length)
274 (set (make-local-variable 'pcomplete-restore-window-delay)
275 eshell-cmpl-restore-window-delay)
ca7aae91
JW
276 (set (make-local-variable 'pcomplete-use-paring)
277 eshell-cmpl-use-paring)
affbf647
GM
278 ;; `pcomplete-arg-quote-list' should only be set after all the
279 ;; load-hooks for any other extension modules have been run, which
280 ;; is true at the time `eshell-mode-hook' is run
affbf647
GM
281 (add-hook 'eshell-mode-hook
282 (function
283 (lambda ()
284 (set (make-local-variable 'pcomplete-arg-quote-list)
285 eshell-special-chars-outside-quoting))) nil t)
affbf647
GM
286 (add-hook 'pcomplete-quote-arg-hook 'eshell-quote-backslash nil t)
287 (define-key eshell-mode-map [(meta tab)] 'lisp-complete-symbol)
288 (define-key eshell-mode-map [(meta control ?i)] 'lisp-complete-symbol)
289 (define-key eshell-command-map [(meta ?h)] 'eshell-completion-help)
290 (define-key eshell-command-map [tab] 'pcomplete-expand-and-complete)
291 (define-key eshell-command-map [(control ?i)]
292 'pcomplete-expand-and-complete)
293 (define-key eshell-command-map [space] 'pcomplete-expand)
294 (define-key eshell-command-map [? ] 'pcomplete-expand)
295 (define-key eshell-mode-map [tab] 'pcomplete)
296 (define-key eshell-mode-map [(control ?i)] 'pcomplete)
297 ;; jww (1999-10-19): Will this work on anything but X?
298 (if (eshell-under-xemacs-p)
299 (define-key eshell-mode-map [iso-left-tab] 'pcomplete-reverse)
300 (define-key eshell-mode-map [(shift iso-lefttab)] 'pcomplete-reverse)
301 (define-key eshell-mode-map [(shift control ?i)] 'pcomplete-reverse))
302 (define-key eshell-mode-map [(meta ??)] 'pcomplete-list))
303
304(defun eshell-completion-command-name ()
305 "Return the command name, possibly sans globbing."
306 (let ((cmd (file-name-nondirectory (pcomplete-arg 'first))))
307 (setq cmd (if (and (> (length cmd) 0)
a129972c 308 (eq (aref cmd 0) eshell-explicit-command-char))
affbf647
GM
309 (substring cmd 1)
310 cmd))
311 (if (eshell-under-windows-p)
312 (file-name-sans-extension cmd)
313 cmd)))
314
315(defun eshell-completion-help ()
316 (interactive)
317 (if (= (point) eshell-last-output-end)
318 (describe-prefix-bindings)
319 (call-interactively 'pcomplete-help)))
320
321(defun eshell-complete-parse-arguments ()
322 "Parse the command line arguments for `pcomplete-argument'."
323 (when (and eshell-no-completion-during-jobs
324 (eshell-interactive-process))
325 (insert-and-inherit "\t")
326 (throw 'pcompleted t))
327 (let ((end (point-marker))
328 (begin (save-excursion (eshell-bol) (point)))
329 (posns (list t))
330 args delim)
331 (when (memq this-command '(pcomplete-expand
332 pcomplete-expand-and-complete))
333 (run-hook-with-args 'eshell-expand-input-functions begin end)
334 (if (= begin end)
335 (end-of-line))
336 (setq end (point-marker)))
337 (if (setq delim
338 (catch 'eshell-incomplete
339 (ignore
340 (setq args (eshell-parse-arguments begin end)))))
341 (cond ((memq (car delim) '(?\{ ?\<))
342 (setq begin (1+ (cadr delim))
343 args (eshell-parse-arguments begin end)))
344 ((eq (car delim) ?\()
345 (lisp-complete-symbol)
346 (throw 'pcompleted t))
347 (t
348 (insert-and-inherit "\t")
349 (throw 'pcompleted t))))
350 (when (get-text-property (1- end) 'comment)
351 (insert-and-inherit "\t")
352 (throw 'pcompleted t))
353 (let ((pos begin))
354 (while (< pos end)
355 (if (get-text-property pos 'arg-begin)
356 (nconc posns (list pos)))
357 (setq pos (1+ pos))))
358 (setq posns (cdr posns))
359 (assert (= (length args) (length posns)))
360 (let ((a args)
361 (i 0)
362 l final)
363 (while a
364 (if (and (consp (car a))
365 (eq (caar a) 'eshell-operator))
366 (setq l i))
367 (setq a (cdr a) i (1+ i)))
368 (and l
369 (setq args (nthcdr (1+ l) args)
370 posns (nthcdr (1+ l) posns))))
371 (assert (= (length args) (length posns)))
34204d80
JW
372 (when (and args (eq (char-syntax (char-before end)) ? )
373 (not (eq (char-before (1- end)) ?\\)))
affbf647
GM
374 (nconc args (list ""))
375 (nconc posns (list (point))))
376 (cons (mapcar
377 (function
378 (lambda (arg)
379 (let ((val
380 (if (listp arg)
381 (let ((result
382 (eshell-do-eval
383 (list 'eshell-commands arg) t)))
384 (assert (eq (car result) 'quote))
385 (cadr result))
386 arg)))
387 (if (numberp val)
388 (setq val (number-to-string val)))
389 (or val ""))))
390 args)
391 posns)))
392
393(defun eshell-complete-commands-list ()
394 "Generate list of applicable, visible commands."
395 (let ((filename (pcomplete-arg)) glob-name)
396 (if (file-name-directory filename)
397 (pcomplete-executables)
398 (if (and (> (length filename) 0)
a129972c 399 (eq (aref filename 0) eshell-explicit-command-char))
affbf647
GM
400 (setq filename (substring filename 1)
401 pcomplete-stub filename
402 glob-name t))
403 (let* ((paths (split-string (getenv "PATH") path-separator))
404 (cwd (file-name-as-directory
405 (expand-file-name default-directory)))
406 (path "") (comps-in-path ())
407 (file "") (filepath "") (completions ()))
408 ;; Go thru each path in the search path, finding completions.
409 (while paths
410 (setq path (file-name-as-directory
411 (expand-file-name (or (car paths) ".")))
412 comps-in-path
413 (and (file-accessible-directory-p path)
414 (file-name-all-completions filename path)))
415 ;; Go thru each completion found, to see whether it should
416 ;; be used.
417 (while comps-in-path
418 (setq file (car comps-in-path)
419 filepath (concat path file))
420 (if (and (not (member file completions)) ;
421 (or (string-equal path cwd)
422 (not (file-directory-p filepath)))
423 (file-executable-p filepath))
424 (setq completions (cons file completions)))
425 (setq comps-in-path (cdr comps-in-path)))
426 (setq paths (cdr paths)))
427 ;; Add aliases which are currently visible, and Lisp functions.
428 (pcomplete-uniqify-list
429 (if glob-name
430 completions
431 (setq completions
432 (append (and (eshell-using-module 'eshell-alias)
433 (funcall (symbol-function 'eshell-alias-completions)
434 filename))
435 (eshell-winnow-list
436 (mapcar
437 (function
438 (lambda (name)
439 (substring name 7)))
440 (all-completions (concat "eshell/" filename)
441 obarray 'functionp))
442 nil '(eshell-find-alias-function))
443 completions))
444 (append (and (or eshell-show-lisp-completions
445 (and eshell-show-lisp-alternatives
446 (null completions)))
447 (all-completions filename obarray 'functionp))
448 completions)))))))
449
450;;; Code:
451
ab5796a9 452;;; arch-tag: 0e914699-673a-45f8-8cbf-82e1dbc571bc
affbf647 453;;; em-cmpl.el ends here