X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/0877d0dc24ee792b9b14592869ea1aa0934aee58..704172e6d4ef5cf66c087b7eb8643a4309726ff7:/lisp/icomplete.el diff --git a/lisp/icomplete.el b/lisp/icomplete.el index 0493a5b49e..0c5a2babd8 100644 --- a/lisp/icomplete.el +++ b/lisp/icomplete.el @@ -1,12 +1,11 @@ ;;; icomplete.el --- minibuffer completion incremental feedback -;; Copyright (C) 1992-1994, 1997, 1999, 2001-2013 Free Software -;; Foundation, Inc. +;; Copyright (C) 1992-1994, 1997, 1999, 2001-2014 +;; Free Software Foundation, Inc. ;; 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. @@ -26,7 +25,7 @@ ;;; Commentary: -;; Loading this package implements a more fine-grained minibuffer +;; Enabling this package implements a more fine-grained minibuffer ;; completion feedback scheme. Prospective completions are concisely ;; indicated within the minibuffer itself, with each successive ;; keystroke. @@ -38,14 +37,7 @@ ;; customize icomplete setup for interoperation with other ;; minibuffer-oriented packages. -;; 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. +;; To enable/disable icomplete mode, use the `icomplete-mode' function. ;; Thanks to everyone for their suggestions for refinements of this ;; package. I particularly have to credit Michael Cook, who @@ -58,13 +50,10 @@ ;;; Code: -;;;_* Provide -(provide 'icomplete) - - (defgroup icomplete nil "Show completions dynamically in minibuffer." :prefix "icomplete-" + :link '(info-link "(emacs)Icomplete") :group 'minibuffer) (defvar icomplete-prospects-length 80) @@ -72,10 +61,35 @@ 'icomplete-prospects-length 'icomplete-prospects-height "23.1") (defcustom icomplete-separator " | " - "String used by icomplete to separate alternatives in the minibuffer." + "String used by Icomplete to separate alternatives in the minibuffer." :type 'string :version "24.4") +(defcustom icomplete-hide-common-prefix t + "When non-nil, hide common prefix from completion candidates. +When nil, show candidates in full." + :type 'boolean + :version "24.4") + +(defcustom icomplete-show-matches-on-no-input nil + "When non-nil, show completions when first prompting for input." + :type 'boolean + :version "24.4") + +(defcustom icomplete-with-completion-tables t + "Specialized completion tables with which Icomplete should operate. +If this is t, Icomplete operates on all tables. +Otherwise this should be a list of the completion tables (e.g., +`internal-complete-buffer') on which Icomplete should operate." + ;; Prior to 24.4, not a user-option, default '(internal-complete-buffer). + :version "24.4" + :type '(choice (const :tag "All" t) + (repeat function))) + +(defface icomplete-first-match '((t :weight bold)) + "Face used by Icomplete for highlighting first match." + :version "24.4") + ;;;_* User Customization variables (defcustom icomplete-prospects-height ;; 20 is an estimated common size for the prompt + minibuffer content, to @@ -83,37 +97,33 @@ (+ 1 (/ (+ icomplete-prospects-length 20) (window-width))) "Maximum number of lines to use in the minibuffer." :type 'integer - :group 'icomplete :version "23.1") (defcustom icomplete-compute-delay .3 "Completions-computation stall, used only with large-number completions. See `icomplete-delay-completions-threshold'." - :type 'number - :group 'icomplete) + :type 'number) (defcustom icomplete-delay-completions-threshold 400 "Pending-completions number over which to apply `icomplete-compute-delay'." - :type 'integer - :group 'icomplete) + :type 'integer) (defcustom icomplete-max-delay-chars 3 - "Maximum number of initial chars to apply icomplete compute delay." - :type 'integer - :group 'icomplete) + "Maximum number of initial chars to apply `icomplete-compute-delay'." + :type 'integer) + +(defvar icomplete-in-buffer nil + "If non-nil, also use Icomplete when completing in non-mini buffers.") (defcustom icomplete-minibuffer-setup-hook nil "Icomplete-specific customization of minibuffer setup. -This hook is run during minibuffer setup if icomplete is active. -It is intended for use in customizing icomplete for interoperation +This hook is run during minibuffer setup if Icomplete is 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)))) + (add-hook 'icomplete-minibuffer-setup-hook + (lambda () (setq-local max-mini-window-height 3))) will constrain Emacs to a maximum minibuffer height of 3 lines when icompletion is occurring." @@ -128,60 +138,50 @@ icompletion is occurring." (defvar icomplete-overlay (make-overlay (point-min) (point-min) nil t t) "Overlay used to display the list of completions.") -;;;_ = icomplete-pre-command-hook -(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) -;;;_ = icomplete-post-command-hook -(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) - -;;;_ = icomplete-with-completion-tables -(defvar icomplete-with-completion-tables '(internal-complete-buffer) - "Specialized completion tables with which icomplete should operate. +(defun icomplete-pre-command-hook () + (let ((non-essential t)) + (icomplete-tidy))) -Icomplete does not operate with any specialized completion tables -except those on this list.") +(defun icomplete-post-command-hook () + (let ((non-essential t)) ;E.g. don't prompt for password! + (icomplete-exhibit))) (defvar icomplete-minibuffer-map (let ((map (make-sparse-keymap))) (define-key map [?\M-\t] 'minibuffer-force-complete) (define-key map [?\C-j] 'minibuffer-force-complete-and-exit) - (define-key map [?\C-s] 'icomplete-forward-completions) - (define-key map [?\C-r] 'icomplete-backward-completions) - map)) + (define-key map [?\C-.] 'icomplete-forward-completions) + (define-key map [?\C-,] 'icomplete-backward-completions) + map) + "Keymap used by `icomplete-mode' in the minibuffer.") (defun icomplete-forward-completions () "Step forward completions by one entry. Second entry becomes the first and can be selected with `minibuffer-force-complete-and-exit'." (interactive) - (let* ((comps (completion-all-sorted-completions)) + (let* ((beg (icomplete--field-beg)) + (end (icomplete--field-end)) + (comps (completion-all-sorted-completions beg end)) (last (last comps))) - (setcdr last (cons (car comps) (cdr last))) - (completion--cache-all-sorted-completions (cdr comps)))) + (when comps + (setcdr last (cons (car comps) (cdr last))) + (completion--cache-all-sorted-completions beg end (cdr comps))))) (defun icomplete-backward-completions () "Step backward completions by one entry. Last entry becomes the first and can be selected with `minibuffer-force-complete-and-exit'." (interactive) - (let* ((comps (completion-all-sorted-completions)) + (let* ((beg (icomplete--field-beg)) + (end (icomplete--field-end)) + (comps (completion-all-sorted-completions beg end)) (last-but-one (last comps 2)) (last (cdr last-but-one))) - (when last + (when (consp last) ; At least two elements in comps (setcdr last-but-one (cdr last)) (push (car last) comps) - (completion--cache-all-sorted-completions comps)))) + (completion--cache-all-sorted-completions beg end comps)))) ;;;_ > icomplete-mode (&optional prefix) ;;;###autoload @@ -189,32 +189,66 @@ Last entry becomes the first and can be selected with "Toggle incremental minibuffer completion (Icomplete mode). With a prefix argument ARG, enable Icomplete mode if ARG is positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil." +the mode if ARG is omitted or nil. + +When this global minor mode is enabled, typing in the minibuffer +continuously displays a list of possible completions that match +the string you have typed. See `icomplete-completions' for a +description of how prospective completions are displayed. + +For more information, see Info node `(emacs)Icomplete'. +For options you can set, `\\[customize-group] icomplete'. + +You can use the following key bindings to navigate and select +completions: + +\\{icomplete-minibuffer-map}" :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))) + (remove-hook 'minibuffer-setup-hook #'icomplete-minibuffer-setup) + (remove-hook 'completion-in-region-mode-hook #'icomplete--in-region-setup) + (when icomplete-mode + (when icomplete-in-buffer + (add-hook 'completion-in-region-mode-hook #'icomplete--in-region-setup)) + (add-hook 'minibuffer-setup-hook #'icomplete-minibuffer-setup))) + +(defun icomplete--completion-table () + (if (window-minibuffer-p) minibuffer-completion-table + (or (nth 2 completion-in-region--data) + (message "In %S (w=%S): %S" + (current-buffer) (selected-window) (window-minibuffer-p))))) +(defun icomplete--completion-predicate () + (if (window-minibuffer-p) minibuffer-completion-predicate + (nth 3 completion-in-region--data))) +(defun icomplete--field-string () + (if (window-minibuffer-p) (minibuffer-contents) + (buffer-substring-no-properties + (nth 0 completion-in-region--data) + (nth 1 completion-in-region--data)))) +(defun icomplete--field-beg () + (if (window-minibuffer-p) (minibuffer-prompt-end) + (nth 0 completion-in-region--data))) +(defun icomplete--field-end () + (if (window-minibuffer-p) (point-max) + (nth 1 completion-in-region--data))) ;;;_ > icomplete-simple-completing-p () (defun icomplete-simple-completing-p () - "Non-nil if current window is minibuffer that's doing simple completion. + "Non-nil if current window is a 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 the completion table is not a function (which would indicate some non-standard, non-simple completion mechanism, - like file-name and other custom-func completions)." + like file-name and other custom-func completions), + and `icomplete-with-completion-tables' doesn't restrict completion." - (and (window-minibuffer-p (selected-window)) - (not executing-kbd-macro) - minibuffer-completion-table - (or (not (functionp minibuffer-completion-table)) - (eq icomplete-with-completion-tables t) - (member minibuffer-completion-table - icomplete-with-completion-tables)))) + (unless executing-kbd-macro + (let ((table (icomplete--completion-table))) + (and table + (or (not (functionp table)) + (eq icomplete-with-completion-tables t) + (member table icomplete-with-completion-tables)))))) ;;;_ > icomplete-minibuffer-setup () (defun icomplete-minibuffer-setup () @@ -224,58 +258,83 @@ Usually run by inclusion in `minibuffer-setup-hook'." (set (make-local-variable 'completion-show-inline-help) nil) (use-local-map (make-composed-keymap icomplete-minibuffer-map (current-local-map))) - (add-hook 'pre-command-hook - (lambda () (let ((non-essential t)) - (run-hooks 'icomplete-pre-command-hook))) - nil t) - (add-hook 'post-command-hook - (lambda () (let ((non-essential t)) ;E.g. don't prompt for password! - (run-hooks 'icomplete-post-command-hook))) - nil t) - (run-hooks 'icomplete-minibuffer-setup-hook))) -; + (add-hook 'pre-command-hook #'icomplete-pre-command-hook nil t) + (add-hook 'post-command-hook #'icomplete-post-command-hook nil t) + (run-hooks 'icomplete-minibuffer-setup-hook) + (when icomplete-show-matches-on-no-input + (icomplete-exhibit)))) + +(defvar icomplete--in-region-buffer nil) + +(defun icomplete--in-region-setup () + (when (or (not completion-in-region-mode) + (and icomplete--in-region-buffer + (not (eq icomplete--in-region-buffer (current-buffer))))) + (with-current-buffer (or icomplete--in-region-buffer (current-buffer)) + (setq icomplete--in-region-buffer nil) + (delete-overlay icomplete-overlay) + (kill-local-variable 'completion-show-inline-help) + (remove-hook 'pre-command-hook 'icomplete-pre-command-hook t) + (remove-hook 'post-command-hook 'icomplete-post-command-hook t) + (message nil))) + (when (and completion-in-region-mode + icomplete-mode (icomplete-simple-completing-p)) + (setq icomplete--in-region-buffer (current-buffer)) + (set (make-local-variable 'completion-show-inline-help) nil) + (let ((tem (assq 'completion-in-region-mode + minor-mode-overriding-map-alist))) + (unless (memq icomplete-minibuffer-map (cdr tem)) + (setcdr tem (make-composed-keymap icomplete-minibuffer-map + (cdr tem))))) + (add-hook 'pre-command-hook 'icomplete-pre-command-hook nil t) + (add-hook 'post-command-hook 'icomplete-post-command-hook nil t))) + ;;;_* Completion ;;;_ > icomplete-tidy () (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'." + "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'." (delete-overlay icomplete-overlay)) ;;;_ > icomplete-exhibit () (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)) + "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)) ;Shouldn't be necessary. (save-excursion (goto-char (point-max)) ; Insert the match-status information: - (if (and (> (point-max) (minibuffer-prompt-end)) - buffer-undo-list ; Wait for some user input. + (if (and (or icomplete-show-matches-on-no-input + (> (icomplete--field-end) (icomplete--field-beg))) (or ;; Don't bother with delay after certain number of chars: - (> (- (point) (field-beginning)) icomplete-max-delay-chars) + (> (- (point) (icomplete--field-beg)) + icomplete-max-delay-chars) ;; Don't delay if the completions are known. completion-all-sorted-completions ;; Don't delay if alternatives number is small enough: - (and (sequencep minibuffer-completion-table) - (< (length minibuffer-completion-table) + (and (sequencep (icomplete--completion-table)) + (< (length (icomplete--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 - (icomplete-completions - (field-string) - minibuffer-completion-table - minibuffer-completion-predicate - (not minibuffer-completion-confirm)))) - (buffer-undo-list t) - deactivate-mark) + (let* ((field-string (icomplete--field-string)) + (text (while-no-input + (icomplete-completions + field-string + (icomplete--completion-table) + (icomplete--completion-predicate) + (if (window-minibuffer-p) + (not minibuffer-completion-confirm))))) + (buffer-undo-list t) + deactivate-mark) ;; Do nothing if while-no-input was aborted. (when (stringp text) (move-overlay icomplete-overlay (point) (point) (current-buffer)) @@ -293,27 +352,31 @@ 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: +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 + (...) - 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 there are multiple possibilities, `icomplete-separator' separates them. - (let* ((md (completion--field-metadata (field-beginning))) - (comps (completion-all-sorted-completions)) +The displays for unambiguous matches have ` [Matched]' appended +\(whether complete or not), or ` [No matches]', if no eligible +matches exist." + (let* ((minibuffer-completion-table candidates) + (minibuffer-completion-predicate predicate) + (md (completion--field-metadata (icomplete--field-beg))) + (comps (completion-all-sorted-completions + (icomplete--field-beg) (icomplete--field-end))) (last (if (consp comps) (last comps))) (base-size (cdr last)) (open-bracket (if require-match "(" "[")) (close-bracket (if require-match ")" "]"))) ;; `concat'/`mapconcat' is the slow part. (if (not (consp comps)) - (format " %sNo matches%s" open-bracket close-bracket) + (progn ;;(debug (format "Candidates=%S field=%S" candidates name)) + (format " %sNo matches%s" open-bracket close-bracket)) (if last (setcdr last nil)) (let* ((most-try (if (and base-size (> base-size 0)) @@ -329,6 +392,7 @@ are exhibited within the square braces.)" ;; a prefix of most, or something else. (compare (compare-strings name nil nil most nil nil completion-ignore-case)) + (ellipsis (if (char-displayable-p ?…) "…" "...")) (determ (unless (or (eq t compare) (eq t most-try) (= (setq compare (1- (abs compare))) (length most))) @@ -339,12 +403,15 @@ are exhibited within the square braces.)" (substring most compare)) ;; Don't bother truncating if it doesn't gain ;; us at least 2 columns. - ((< compare 3) most) - (t (concat "…" (substring most compare)))) + ((< compare (+ 2 (string-width ellipsis))) most) + (t (concat ellipsis (substring most compare)))) close-bracket))) ;;"-prospects" - more than one candidate - (prospects-len (+ (length determ) 6 ;; take {,...} into account - (string-width (buffer-string)))) + (prospects-len (+ (string-width + (or determ (concat open-bracket close-bracket))) + (string-width icomplete-separator) + (+ 2 (string-width ellipsis)) ;; take {…} into account + (string-width (buffer-string)))) (prospects-max ;; Max total length to use, including the minibuffer content. (* (+ icomplete-prospects-height @@ -352,48 +419,77 @@ are exhibited within the square braces.)" ;; one line, increase the allowable space accordingly. (/ prospects-len (window-width))) (window-width))) + ;; Find the common prefix among `comps'. + ;; We can't use the optimization below because its assumptions + ;; aren't always true, e.g. when completion-cycling (bug#10850): + ;; (if (eq t (compare-strings (car comps) nil (length most) + ;; most nil nil completion-ignore-case)) + ;; ;; Common case. + ;; (length most) + ;; Else, use try-completion. + (prefix (when icomplete-hide-common-prefix + (try-completion "" comps))) (prefix-len - ;; Find the common prefix among `comps'. - ;; We can't use the optimization below because its assumptions - ;; aren't always true, e.g. when completion-cycling (bug#10850): - ;; (if (eq t (compare-strings (car comps) nil (length most) - ;; most nil nil completion-ignore-case)) - ;; ;; Common case. - ;; (length most) - ;; Else, use try-completion. - (let ((comps-prefix (try-completion "" comps))) - (and (stringp comps-prefix) - (length comps-prefix)))) ;;) - - prospects most-is-exact comp limit) - (if (eq most-try t) ;; (or (null (cdr comps)) + (and (stringp prefix) + ;; Only hide the prefix if the corresponding info + ;; is already displayed via `most'. + (string-prefix-p prefix most t) + (length prefix))) ;;) + prospects comp limit) + (if (or (eq most-try t) (not (consp (cdr comps)))) (setq prospects nil) + (when (member name comps) + ;; NAME is complete but not unique. This scenario poses + ;; following UI issues: + ;; + ;; - When `icomplete-hide-common-prefix' is non-nil, NAME + ;; is stripped empty. This would make the entry + ;; inconspicuous. + ;; + ;; - Due to sorting of completions, NAME may not be the + ;; first of the prospects and could be hidden deep in + ;; the displayed string. + ;; + ;; - Because of `icomplete-prospects-height' , NAME may + ;; not even be displayed to the user. + ;; + ;; To circumvent all the above problems, provide a visual + ;; cue to the user via an "empty string" in the try + ;; completion field. + (setq determ (concat open-bracket "" close-bracket))) + ;; Compute prospects for display. (while (and comps (not limit)) (setq comp (if prefix-len (substring (car comps) prefix-len) (car comps)) comps (cdr comps)) - (cond ((string-equal comp "") (setq most-is-exact t)) - ((member comp prospects)) - (t (setq prospects-len - (+ (string-width comp) 1 prospects-len)) + (setq prospects-len + (+ (string-width comp) + (string-width icomplete-separator) + prospects-len)) (if (< prospects-len prospects-max) (push comp prospects) - (setq limit t)))))) + (setq limit t)))) + (setq prospects (nreverse prospects)) + ;; Decorate first of the prospects. + (when prospects + (let ((first (copy-sequence (pop prospects)))) + (put-text-property 0 (length first) + 'face 'icomplete-first-match first) + (push first prospects))) ;; Restore the base-size info, since completion-all-sorted-completions ;; is cached. (if last (setcdr last base-size)) (if prospects (concat determ "{" - (and most-is-exact - (substring icomplete-separator - (string-match "[^ ]" icomplete-separator))) - (mapconcat 'identity (nreverse prospects) - icomplete-separator) - (and limit (concat icomplete-separator "…")) + (mapconcat 'identity prospects icomplete-separator) + (and limit (concat icomplete-separator ellipsis)) "}") (concat determ " [Matched]")))))) +;;;_* Provide +(provide 'icomplete) + ;;_* Local emacs vars. ;;Local variables: ;;allout-layout: (-2 :)