]> code.delx.au - gnu-emacs/blobdiff - lisp/icomplete.el
(ispell): New function, replacing an alias.
[gnu-emacs] / lisp / icomplete.el
index 025af152a9d071e1d94f47a89a22512cbf0dab1d..344cd9fe18f300a2c93369f55f84d5293e3eecaa 100644 (file)
@@ -1,10 +1,11 @@
 ;;; icomplete.el --- minibuffer completion incremental feedback
 
-;; Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993, 1994, 1997, 1999 Free Software Foundation, Inc.
 
-;; Author: Ken Manheimer <klm@nist.gov>
-;; Maintainer: Ken Manheimer <klm@nist.gov>
-;; Created: Mar 1993 klm@nist.gov - first release to usenet
+;; Author: Ken Manheimer <klm@i.am>
+;; Maintainer: Ken Manheimer <klm@i.am>
+;; Created: Mar 1993 Ken Manheimer, klm@nist.gov - first release to usenet
+;; Last update: Ken Manheimer <klm@i.am>, 11/18/1999.
 ;; Keywords: help, abbrev
 
 ;; This file is part of GNU Emacs.
 ;; indicated within the minibuffer itself, with each successive
 ;; keystroke.
 
-;; See 'icomplete-completions' docstring for a description of the
+;; See `icomplete-completions' docstring for a description of the
 ;; icomplete display format.
 
 ;; See the `icomplete-minibuffer-setup-hook' docstring for a means to
 ;; customize icomplete setup for interoperation with other
 ;; minibuffer-oriented packages.
 
-;; To activate icomplete mode, simply load the package.  You can
-;; subsequently deactivate it by invoking the function icomplete-mode
-;; with a negative prefix-arg (C-U -1 ESC-x icomplete-mode).  Also,
-;; you can prevent activation of the mode during package load by
-;; first setting the variable `icomplete-mode' to nil.  Icompletion
-;; can be enabled any time after the package is loaded by invoking
-;; icomplete-mode without a prefix arg.
+;; To activate icomplete mode, load the package and use the
+;; `icomplete-mode' function.  You can subsequently deactivate it by
+;; invoking the function icomplete-mode with a negative prefix-arg
+;; (C-U -1 ESC-x icomplete-mode).  Also, you can prevent activation of
+;; the mode during package load by first setting the variable
+;; `icomplete-mode' to nil.  Icompletion can be enabled any time after
+;; the package is loaded by invoking icomplete-mode without a prefix
+;; arg.
 
 ;; Thanks to everyone for their suggestions for refinements of this
 ;; package.  I particularly have to credit Michael Cook, who
 ;; implemented an incremental completion style in his 'iswitch'
 ;; functions that served as a model for icomplete.  Some other
-;; contributors: Noah Freidman (restructuring as minor mode), Colin
-;; Rafferty (lemacs reconciliation), Lars Lindberg, RMS, and
-;; others.
+;; contributors: Noah Friedman (restructuring as minor mode), Colin
+;; Rafferty (lemacs reconciliation), Lars Lindberg, RMS, and others.
 
 ;; klm.
 
 ;;;_* Provide
 (provide 'icomplete)
 
-;;;_* User Customization variables
 
-;;;_* Initialization
-;;;_  = icomplete-minibuffer-setup-hook
-(defvar icomplete-minibuffer-setup-hook nil
+(defgroup icomplete nil
+  "Show completions dynamically in minibuffer."
+  :prefix "icomplete-"
+  :group 'minibuffer)
+
+(defcustom icomplete-mode nil
+  "*Toggle incremental minibuffer completion.
+As text is typed into the minibuffer, prospective completions are indicated 
+in the minibuffer.
+Setting this variable directly does not take effect;
+use either \\[customize] or the function `icomplete-mode'."
+  :set (lambda (symbol value)
+        (icomplete-mode (if value 1 -1)))
+  :initialize 'custom-initialize-default
+  :type 'boolean
+  :group 'icomplete
+  :require 'icomplete)
+
+;;;_* User Customization variables
+(defcustom icomplete-prospects-length 80
+  "*Length of string displaying the prospects."
+  :type 'integer
+  :group 'icomplete)
+
+(defcustom icomplete-compute-delay .3
+  "*Completions-computation stall, used only with large-number
+completions - see `icomplete-delay-completions-threshold'."
+  :type 'number
+  :group 'icomplete)
+
+(defcustom icomplete-delay-completions-threshold 400
+  "*Pending-completions number over which to apply icomplete-compute-delay."
+  :type 'integer
+  :group 'icomplete)
+
+(defcustom icomplete-max-delay-chars 3
+  "*Maximum number of initial chars to apply icomplete compute delay."
+  :type 'integer
+  :group 'icomplete)
+
+(defcustom icomplete-show-key-bindings t
+  "*If non-nil, show key bindings as well as completion for sole matches."
+  :type 'boolean
+  :group 'icomplete)
+
+(defcustom icomplete-minibuffer-setup-hook nil
   "*Icomplete-specific customization of minibuffer setup.
 
 This hook is run during minibuffer setup iff icomplete will be active.
 It is intended for use in customizing icomplete for interoperation
 with other packages.  For instance:
 
-  \(add-hook 'icomplete-minibuffer-setup-hook 
+  \(add-hook 'icomplete-minibuffer-setup-hook
            \(function
             \(lambda ()
               \(make-local-variable 'resize-minibuffer-window-max-height)
               \(setq resize-minibuffer-window-max-height 3))))
 
 will constrain rsz-mini to a maximum minibuffer height of 3 lines when
-icompletion is occurring.")
+icompletion is occurring."
+  :type 'hook
+  :group 'icomplete)
+
+
+;;;_* Initialization
 
 ;;;_ + Internal Variables
-;;;_  = icomplete-mode
-(defvar icomplete-mode t
-  "Non-nil enables incremental minibuffer completion, once
-`\\[icomplete-mode]' function has set things up.")
 ;;;_  = icomplete-eoinput 1
 (defvar icomplete-eoinput 1
   "Point where minibuffer input ends and completion info begins.")
@@ -107,11 +151,30 @@ Use `icomplete-mode' function to set it up properly for incremental
 minibuffer completion.")
 (add-hook 'icomplete-post-command-hook 'icomplete-exhibit)
 
+(defun icomplete-get-keys (func-name)
+  "Return strings naming keys bound to `func-name', or nil if none.
+Examines the prior, not current, buffer, presuming that current buffer
+is minibuffer."
+  (if (commandp func-name)
+    (save-excursion
+      (let* ((sym (intern func-name))
+            (buf (other-buffer))
+            (map (save-excursion (set-buffer buf) (current-local-map)))
+            (keys (where-is-internal sym map)))
+       (if keys
+           (concat "<"
+                   (mapconcat 'key-description
+                              (sort keys
+                                    #'(lambda (x y)
+                                        (< (length x) (length y))))
+                              ", ")
+                   ">"))))))
+
 ;;;_ > icomplete-mode (&optional prefix)
 ;;;###autoload
 (defun icomplete-mode (&optional prefix)
-  "Activate incremental minibuffer completion for this emacs session,
-or deactivate with negative prefix arg."
+  "Activate incremental minibuffer completion for this Emacs session.
+Deactivates with negative universal argument."
   (interactive "p")
   (or prefix (setq prefix 0))
   (cond ((>= prefix 0)
@@ -123,7 +186,6 @@ or deactivate with negative prefix arg."
 
 ;;;_ > icomplete-simple-completing-p ()
 (defun icomplete-simple-completing-p ()
-
   "Non-nil if current window is minibuffer that's doing simple completion.
 
 Conditions are:
@@ -154,7 +216,9 @@ Usually run by inclusion in `minibuffer-setup-hook'."
                               (run-hooks 'icomplete-post-command-hook)))
                   nil t)
         (run-hooks 'icomplete-minibuffer-setup-hook))))
-\f
+;\f
+
+
 ;;;_* Completion
 
 ;;;_ > icomplete-tidy ()
@@ -182,7 +246,7 @@ and `minibuffer-setup-hook'."
 Should be run via minibuffer `post-command-hook'.  See `icomplete-mode'
 and `minibuffer-setup-hook'."
   (if (icomplete-simple-completing-p)
-      (let ((contents (buffer-substring (point-min)(point-max)))
+      (let ((contents (buffer-substring (minibuffer-prompt-end)(point-max)))
            (buffer-undo-list t))
        (save-excursion
          (goto-char (point-max))
@@ -194,7 +258,22 @@ and `minibuffer-setup-hook'."
              (make-local-variable 'icomplete-eoinput))
          (setq icomplete-eoinput (point))
                                         ; Insert the match-status information:
-         (if (> (point-max) 1)
+         (if (and (> (point-max) 1)
+                  (or
+                   ;; Don't bother with delay after certain number of chars:
+                   (> (point-max) icomplete-max-delay-chars)
+                   ;; Don't delay if alternatives number is small enough:
+                   (if minibuffer-completion-table
+                       (cond ((numberp minibuffer-completion-table)
+                              (< minibuffer-completion-table
+                                 icomplete-delay-completions-threshold))
+                             ((sequencep minibuffer-completion-table)
+                              (< (length minibuffer-completion-table)
+                                 icomplete-delay-completions-threshold))
+                             ))
+                   ;; Delay - give some grace time for next keystroke, before
+                   ;; embarking on computing completions:
+                   (sit-for icomplete-compute-delay)))
              (insert-string
               (icomplete-completions contents
                                      minibuffer-completion-table
@@ -219,64 +298,65 @@ one of \(), \[], or \{} pairs.  The choice of brackets is as follows:
 
 The displays for unambiguous matches have ` [Matched]' appended
 \(whether complete or not), or ` \[No matches]', if no eligible
-matches exist."
+matches exist.  \(Keybindings for uniquely matched commands
+are exhibited within the square braces.)"
+
+  ;; 'all-completions' doesn't like empty
+  ;; minibuffer-completion-table's (ie: (nil))
+  (if (and (listp candidates) (null (car candidates)))
+      (setq candidates nil))
 
   (let ((comps (all-completions name candidates predicate))
                                         ; "-determined" - only one candidate
         (open-bracket-determined (if require-match "(" "["))
-        (close-bracket-determined (if require-match ")" "]"))
+        (close-bracket-determined (if require-match ")" "]")))
+    ;; `concat'/`mapconcat' is the slow part.  With the introduction of
+    ;; `icomplete-prospects-length', there is no need for `catch'/`throw'.
+    (if (null comps) (format " %sNo matches%s"
+                            open-bracket-determined
+                            close-bracket-determined)
+      (let* ((most-try (try-completion name (mapcar (function list) comps)))
+            (most (if (stringp most-try) most-try (car comps)))
+            (most-len (length most))
+            (determ (and (> most-len (length name))
+                         (concat open-bracket-determined
+                                 (substring most (length name))
+                                 close-bracket-determined)))
+            (open-bracket-prospects "{")
+            (close-bracket-prospects "}")
                                         ;"-prospects" - more than one candidate
-        (open-bracket-prospects "{")
-        (close-bracket-prospects "}")
-        )
-    (cond ((null comps) (format " %sNo matches%s"
-                                open-bracket-determined
-                                close-bracket-determined))
-          ((null (cdr comps))           ;one match
-           (concat (if (and (> (length (car comps))
-                               (length name)))
-                       (concat open-bracket-determined
-                               (substring (car comps) (length name))
-                               close-bracket-determined)
-                     "")
-                   " [Matched]"))
-          (t                            ;multiple matches
-           (let* ((most (try-completion name candidates predicate))
-                  (most-len (length most))
-                  most-is-exact
-                  (alternatives
-                   (apply
-                    (function concat)
-                    (cdr (apply
-                         (function nconc)
-                         (mapcar '(lambda (com)
-                                    (if (= (length com) most-len)
-                                        ;; Most is one exact match,
-                                        ;; note that and leave out
-                                        ;; for later indication:
-                                        (progn
-                                          (setq most-is-exact t)
-                                          ())
-                                      (list ","
-                                            (substring com
-                                                       most-len))))
-                                 comps))))))
-             (concat (and (> most-len (length name))
-                          (concat open-bracket-determined
-                                  (substring most (length name))
-                                  close-bracket-determined))
-                     open-bracket-prospects
-                     (if most-is-exact
-                         (concat "," alternatives)
-                       alternatives)
-                     close-bracket-prospects))))))
-
-;;;_ + Initialization
-;;; If user hasn't setq-default icomplete-mode to nil, then setup for
-;;; activation:
-(if icomplete-mode
-    (icomplete-mode))
+            (prospects-len 0)
+            prospects most-is-exact comp)
+       (if (eq most-try t)
+           (setq prospects nil)
+         (while (and comps (< prospects-len icomplete-prospects-length))
+           (setq comp (substring (car comps) most-len)
+                 comps (cdr comps))
+           (cond ((string-equal comp "") (setq most-is-exact t))
+                 ((member comp prospects))
+                 (t (setq prospects (cons comp prospects)
+                          prospects-len (+ (length comp) 1 prospects-len))))))
+       (if prospects
+           (concat determ
+                   open-bracket-prospects
+                   (and most-is-exact ",")
+                   (mapconcat 'identity
+                              (sort prospects (function string-lessp))
+                              ",")
+                   (and comps ",...")
+                   close-bracket-prospects)
+         (concat determ
+                 " [Matched"
+                 (let ((keys (and icomplete-show-key-bindings
+                                  (commandp (intern-soft most))
+                                  (icomplete-get-keys most))))
+                   (if keys
+                       (concat "; " keys)
+                     ""))
+                 "]"))))))
 
+(if icomplete-mode
+    (icomplete-mode 1))
 
 ;;;_* Local emacs vars.
 ;;;Local variables:
@@ -284,4 +364,3 @@ matches exist."
 ;;;End:
 
 ;;; icomplete.el ends here
-