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