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