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