X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/92f7d0036fe5eeb041a9cadc9560dc1645a3fb4f..b0c9a334c2f0eb881eff47f590997e746cc3bdb3:/lisp/icomplete.el diff --git a/lisp/icomplete.el b/lisp/icomplete.el index f90100fd4d..085c111d85 100644 --- a/lisp/icomplete.el +++ b/lisp/icomplete.el @@ -1,10 +1,12 @@ -;;;_. icomplete.el - minibuffer completion incremental feedback +;;; icomplete.el --- minibuffer completion incremental feedback -;; Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. +;; Copyright (C) 1992, 1993, 1994, 1997, 1999, 2001, 2002, 2003, +;; 2004, 2005 Free Software Foundation, Inc. -;; Author: Ken Manheimer -;; Maintainer: Ken Manheimer -;; Created: Mar 1993 klm@nist.gov - first release to usenet +;; Author: Ken Manheimer +;; Maintainer: Ken Manheimer +;; Created: Mar 1993 Ken Manheimer, klm@nist.gov - first release to usenet +;; Last update: Ken Manheimer , 11/18/1999. ;; Keywords: help, abbrev ;; This file is part of GNU Emacs. @@ -21,12 +23,8 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;; This file is also part of XEmacs. -;; Hacked for XEmacs: David Hughes 7th September 1995 -;; With some integration and refinement by Ken Manheimer, May 1997 +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: @@ -35,33 +33,28 @@ ;; 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. - -;; This version of icomplete runs on Emacs 19.18 and later. (It -;; depends on the incorporation of minibuffer-setup-hook.) The elisp -;; archives, ftp://archive.cis.ohio-state.edu/pub/gnu/emacs/elisp-archive, -;; probably still has a version that works in GNU Emacs v18. +;; 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. @@ -70,40 +63,63 @@ ;;;_* Provide (provide 'icomplete) + +(defgroup icomplete nil + "Show completions dynamically in minibuffer." + :prefix "icomplete-" + :group 'minibuffer) + ;;;_* User Customization variables -(defvar icomplete-compute-delay .3 - "*Completions-computation stall, used only with large-number -completions - see `icomplete-delay-completions-threshold'.") -(defvar icomplete-delay-completions-threshold 400 - "*Pending-completions number over which to apply icomplete-compute-delay.") -(defvar icomplete-max-delay-chars 3 - "*Maximum number of initial chars to apply icomplete compute delay.") +(defcustom icomplete-prospects-length 80 + "*Length of string displaying the prospects." + :type 'integer + :group 'icomplete) -;;;_* Initialization -;;;_ = icomplete-minibuffer-setup-hook -(defvar icomplete-minibuffer-setup-hook nil +(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: +with other features and packages. For instance: \(add-hook 'icomplete-minibuffer-setup-hook \(function \(lambda () - \(make-local-variable 'resize-minibuffer-window-max-height) - \(setq resize-minibuffer-window-max-height 3)))) + \(make-local-variable 'max-mini-window-height) + \(setq max-mini-window-height 3)))) + +will constrain Emacs to a maximum minibuffer height of 3 lines when +icompletion is occurring." + :type 'hook + :group 'icomplete) + -will constrain rsz-mini to a maximum minibuffer height of 3 lines when -icompletion is occurring.") +;;;_* 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 +;;;_ = icomplete-eoinput nil +(defvar icomplete-eoinput nil "Point where minibuffer input ends and completion info begins.") (make-variable-buffer-local 'icomplete-eoinput) ;;;_ = icomplete-pre-command-hook @@ -123,21 +139,16 @@ Use `icomplete-mode' function to set it up properly for incremental minibuffer completion.") (add-hook 'icomplete-post-command-hook 'icomplete-exhibit) -(defvar icomplete-show-key-bindings (string-match "XEmacs\\|Lucid" - emacs-version) - "When non-nil show key bindings as well as completion when matching -a command. Currently working only for XEmacs - see `icomplete-get-keys'.") - (defun icomplete-get-keys (func-name) - "Return the keys `func-name' is bound to as a string, or nil if none. - NOTE that this depends on `owindow' minbuf setting and `current-local-map' - taking arg, both present in XEmacs but not present in mainline GNU Emacs - 19.34." - (when (commandp 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 (set-buffer (window-buffer owindow))) - (keys (where-is-internal sym (current-local-map buf)))) + (buf (other-buffer)) + (map (save-excursion (set-buffer buf) (current-local-map))) + (keys (where-is-internal sym map))) (if keys (concat "<" (mapconcat 'key-description @@ -149,52 +160,48 @@ a command. Currently working only for XEmacs - see `icomplete-get-keys'.") ;;;_ > icomplete-mode (&optional prefix) ;;;###autoload -(defun icomplete-mode (&optional prefix) - "Activate incremental minibuffer completion for this emacs session, -or deactivate with negative prefix arg." - (interactive "p") - (or prefix (setq prefix 0)) - (cond ((>= prefix 0) - (setq icomplete-mode t) - ;; The following is not really necessary after first time - - ;; no great loss. - (add-hook 'minibuffer-setup-hook 'icomplete-minibuffer-setup)) - (t (setq icomplete-mode nil)))) +(define-minor-mode icomplete-mode + "Toggle incremental minibuffer completion for this Emacs session. +With a numeric argument, turn Icomplete mode on iff ARG is positive." + :global t :group 'icomplete + (if icomplete-mode + ;; The following is not really necessary after first time - + ;; no great loss. + (add-hook 'minibuffer-setup-hook 'icomplete-minibuffer-setup) + (remove-hook 'minibuffer-setup-hook 'icomplete-minibuffer-setup))) ;;;_ > icomplete-simple-completing-p () (defun icomplete-simple-completing-p () - "Non-nil if current window is minibuffer that's doing simple completion. Conditions are: the selected window is a minibuffer, and not in the middle of macro execution, - and minibuffer-completion-table is not a symbol (which would + and `minibuffer-completion-table' is not a symbol (which would indicate some non-standard, non-simple completion mechanism, like file-name and other custom-func completions)." (and (window-minibuffer-p (selected-window)) (not executing-kbd-macro) - (not (symbolp minibuffer-completion-table)))) + minibuffer-completion-table + ;; (or minibuffer-completing-file-name + (not (functionp minibuffer-completion-table)))) ;; ) ;;;_ > icomplete-minibuffer-setup () -;;;###autoload (defun icomplete-minibuffer-setup () "Run in minibuffer on activation to establish incremental completion. Usually run by inclusion in `minibuffer-setup-hook'." - (cond ((and icomplete-mode (icomplete-simple-completing-p)) - (make-local-hook 'pre-command-hook) - (add-hook 'pre-command-hook - (function (lambda () - (run-hooks 'icomplete-pre-command-hook))) - nil t) - (make-local-hook 'post-command-hook) - (add-hook 'post-command-hook - (function (lambda () - (run-hooks 'icomplete-post-command-hook))) - nil t) - (run-hooks 'icomplete-minibuffer-setup-hook)))) - + (when (and icomplete-mode (icomplete-simple-completing-p)) + (add-hook 'pre-command-hook + (lambda () (run-hooks 'icomplete-pre-command-hook)) + nil t) + (add-hook 'post-command-hook + (lambda () (run-hooks 'icomplete-post-command-hook)) + nil t) + (run-hooks 'icomplete-minibuffer-setup-hook))) +; + + ;;;_* Completion ;;;_ > icomplete-tidy () @@ -202,61 +209,49 @@ Usually run by inclusion in `minibuffer-setup-hook'." "Remove completions display \(if any) prior to new user input. Should be run in on the minibuffer `pre-command-hook'. See `icomplete-mode' and `minibuffer-setup-hook'." - (if (icomplete-simple-completing-p) - (if (and (boundp 'icomplete-eoinput) - icomplete-eoinput) + (when icomplete-eoinput - (if (> icomplete-eoinput (point-max)) - ;; Oops, got rug pulled out from under us - reinit: - (setq icomplete-eoinput (point-max)) - (let ((buffer-undo-list buffer-undo-list )) ; prevent entry - (delete-region icomplete-eoinput (point-max)))) + (unless (>= icomplete-eoinput (point-max)) + (let ((buffer-undo-list t)) ; prevent entry + (delete-region icomplete-eoinput (point-max)))) - ;; Reestablish the local variable 'cause minibuffer-setup is weird: - (make-local-variable 'icomplete-eoinput) - (setq icomplete-eoinput 1)))) + ;; Reestablish the safe value. + (setq icomplete-eoinput nil))) ;;;_ > icomplete-exhibit () (defun icomplete-exhibit () "Insert icomplete completions display. - 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))) - (buffer-undo-list t)) - (save-excursion - (goto-char (point-max)) - ; Register the end of input, so we - ; know where the extra stuff - ; (match-status info) begins: - (if (not (boundp 'icomplete-eoinput)) - ;; In case it got wiped out by major mode business: - (make-local-variable 'icomplete-eoinput)) - (setq icomplete-eoinput (point)) + (when (icomplete-simple-completing-p) + (save-excursion + (goto-char (point-max)) + ;; Register the end of input, so we know where the extra stuff + ;; (match-status info) begins: + (setq icomplete-eoinput (point)) ; Insert the match-status information: - (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 - minibuffer-completion-predicate - (not - minibuffer-completion-confirm)))))))) + (if (and (> (point-max) (minibuffer-prompt-end)) + buffer-undo-list ; Wait for some user input. + (or + ;; Don't bother with delay after certain number of chars: + (> (- (point) (field-beginning)) icomplete-max-delay-chars) + ;; Don't delay if alternatives number is small enough: + (and (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))) + (let ((text (while-no-input + (list + (icomplete-completions + (field-string) + minibuffer-completion-table + minibuffer-completion-predicate + (not minibuffer-completion-confirm))))) + (buffer-undo-list t)) + ;; Do nothing if while-no-input was aborted. + (if (consp text) (insert (car text)))))))) ;;;_ > icomplete-completions (name candidates predicate require-match) (defun icomplete-completions (name candidates predicate require-match) @@ -275,7 +270,7 @@ 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. \(In XEmacs, keybindings for matched commands, if any, +matches exist. \(Keybindings for uniquely matched commands are exhibited within the square braces.)" ;; 'all-completions' doesn't like empty @@ -286,87 +281,52 @@ are exhibited within the square braces.)" (let ((comps (all-completions name candidates predicate)) ; "-determined" - only one candidate (open-bracket-determined (if require-match "(" "[")) - (close-bracket-determined (if require-match ")" "]")) - ;"-prospects" - more than one candidate - (open-bracket-prospects "{") - (close-bracket-prospects "}") - ) - (catch 'input - (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" - (let ((keys (and icomplete-show-key-bindings - (commandp (intern-soft (car comps))) - (icomplete-get-keys (car comps))))) - (if keys - (concat "; " keys) - "")) - "]")) - (t ;multiple matches - (let* ((most - (try-completion name candidates - (and predicate - ;; Wrap predicate in impatience - ie, - ;; `throw' up when pending input is - ;; noticed. Adds some overhead to - ;; predicate, but should be worth it. - (function - (lambda (item) - (if (input-pending-p) - (throw 'input "") - (apply predicate - item nil))))))) - (most-len (length most)) - most-is-exact - (alternatives - (substring - (apply (function concat) - (mapcar (function - (lambda (com) - (if (input-pending-p) - (throw 'input "")) - (if (= (length com) most-len) - ;; Most is one exact match, - ;; note that and leave out - ;; for later indication: - (progn - (setq most-is-exact t) - ()) - (concat "," - (substring com - most-len))))) - comps)) - 1))) - (concat (and (> most-len (length name)) - (concat open-bracket-determined - (substring most (length name)) - close-bracket-determined)) - open-bracket-prospects - (if most-is-exact - ;; Add a ',' at the front to indicate "complete but - ;; not unique": - (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)) - + (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))) + ;;"-prospects" - more than one candidate + (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 + "{" + (and most-is-exact ",") + (mapconcat 'identity + (sort prospects (function string-lessp)) + ",") + (and comps ",...") + "}") + (concat determ + " [Matched" + (let ((keys (and icomplete-show-key-bindings + (commandp (intern-soft most)) + (icomplete-get-keys most)))) + (if keys (concat "; " keys) "")) + "]")))))) ;;;_* Local emacs vars. ;;;Local variables: ;;;outline-layout: (-2 :) ;;;End: +;; arch-tag: 339ec25a-0741-4eb6-be63-997532e89b0f ;;; icomplete.el ends here