(provide 'icomplete)
(defgroup icomplete nil
"Show completions dynamically in minibuffer."
:prefix "icomplete-"
:group 'minibuffer)
(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 features and packages. For instance:
\(add-hook 'icomplete-minibuffer-setup-hook
\(function
\(lambda ()
\(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)
(defvar icomplete-eoinput nil
"Point where minibuffer input ends and completion info begins.")
(make-variable-buffer-local 'icomplete-eoinput)
(defvar icomplete-pre-command-hook nil
"Incremental-minibuffer-completion pre-command-hook.
Is run in minibuffer before user input when `icomplete-mode' is non-nil.
Use `icomplete-mode' function to set it up properly for incremental
minibuffer completion.")
(add-hook 'icomplete-pre-command-hook 'icomplete-tidy)
(defvar icomplete-post-command-hook nil
"Incremental-minibuffer-completion post-command-hook.
Is run in minibuffer after user input when `icomplete-mode' is non-nil.
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 nil t))
(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))))
", ")
">"))))))
(defvar icomplete-with-completion-tables '(internal-complete-buffer)
"Specialized completion tables with which icomplete should operate.
Icomplete does not operate with any specialized completion tables
except those on this list.")
(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
(add-hook 'minibuffer-setup-hook 'icomplete-minibuffer-setup)
(remove-hook 'minibuffer-setup-hook 'icomplete-minibuffer-setup)))
(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
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)
minibuffer-completion-table
(or (not (functionp minibuffer-completion-table))
(member minibuffer-completion-table
icomplete-with-completion-tables))))
(defun icomplete-minibuffer-setup ()
"Run in minibuffer on activation to establish incremental completion.
Usually run by inclusion in `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)))
(defun icomplete-tidy ()
"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'."
(when (and icomplete-mode icomplete-eoinput)
(unless (>= icomplete-eoinput (point-max))
(let ((buffer-undo-list t) deactivate-mark)
(delete-region icomplete-eoinput (point-max))))
(setq icomplete-eoinput nil)))
(defun icomplete-exhibit ()
"Insert icomplete completions display.
Should be run via minibuffer `post-command-hook'. See `icomplete-mode'
and `minibuffer-setup-hook'."
(when (and icomplete-mode (icomplete-simple-completing-p))
(save-excursion
(goto-char (point-max))
(setq icomplete-eoinput (point))
(if (and (> (point-max) (minibuffer-prompt-end))
buffer-undo-list (or
(> (- (point) (field-beginning)) icomplete-max-delay-chars)
(and (sequencep minibuffer-completion-table)
(< (length minibuffer-completion-table)
icomplete-delay-completions-threshold))
(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)
deactivate-mark)
(if (consp text) (insert (car text))))))))
(defun icomplete-completions (name candidates predicate require-match)
"Identify prospective candidates for minibuffer completion.
The display is updated with each minibuffer keystroke during
minibuffer completion.
Prospective completion suffixes (if any) are displayed, bracketed by
one of \(), \[], or \{} pairs. The choice of brackets is as follows:
\(...) - a single prospect is identified and matching is enforced,
\[...] - a single prospect is identified but matching is optional, or
\{...} - multiple prospects, separated by commas, are indicated, and
further input is required to distinguish a single one.
The displays for unambiguous matches have ` [Matched]' appended
\(whether complete or not), or ` \[No matches]', if no eligible
matches exist. \(Keybindings for uniquely matched commands
are exhibited within the square braces.)"
(if (and (listp candidates) (null (car candidates)))
(setq candidates nil))
(let ((comps (all-completions name candidates predicate))
(open-bracket-determined (if require-match "(" "["))
(close-bracket-determined (if require-match ")" "]")))
(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-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) ""))
"]"))))))