diff options
| author | João Távora | 2021-05-30 16:26:02 +0100 |
|---|---|---|
| committer | João Távora | 2021-06-01 10:40:54 +0100 |
| commit | 05ab6e53e2cc82edb0b0916c880bdaa269267528 (patch) | |
| tree | ee170ac1dda968069aa440a3885ef74a0cea6a69 | |
| parent | 062f5aa640db1b8208f9c45dd12fea08e85658d9 (diff) | |
| download | emacs-05ab6e53e2cc82edb0b0916c880bdaa269267528.tar.gz emacs-05ab6e53e2cc82edb0b0916c880bdaa269267528.zip | |
Improve icomplete-vertical-mode and fido-vertical-mode
This mode is intended to be used with Icomplete ('M-x icomplete-mode')
or Fido ('M-x fido-mode'), to display the list of completions
candidates vertically instead of horizontally. When used with
Icomplete, completions are rotated and selection kept at the top.
When used with Fido, completions scroll like a typical dropdown
widget.
If the dropdown behaviour is desired for Icomplete (instead of
rotation), icomplete-scroll can be adjusted separately by the user.
* etc/NEWS (icomplete-vertical-mode): Reword.
* lisp/icomplete.el (simple): Require it.
(icomplete-selected-match): New face.
(icomplete-scroll): New user-visible var.
(icomplete-forward-completions): Rework.
(icomplete-backward-completions): Rework.
(icomplete--fido-mode-setup): Prefer icomplete-scroll according to
icomplete-vertical mode.
(icomplete-minibuffer-setup): Initialize icomplete--scrolled-completions.
(fido-vertical-mode): An alias for icomplete-vertical-mode.
(icomplete-exhibit): Init icomplete--scrolled-past. Adjust overlay.
(icomplete--render-vertical): New helper.
(icomplete--sorted-completions): If cache is stale, also
invalidate icomplete--scrolled-past.
(icomplete-completions): Rework. Mostly reformat.
* lisp/simple.el (max-mini-window-lines): New helper.
(display-message-or-buffer): Use it.
| -rw-r--r-- | etc/NEWS | 10 | ||||
| -rw-r--r-- | lisp/icomplete.el | 362 | ||||
| -rw-r--r-- | lisp/simple.el | 21 |
3 files changed, 257 insertions, 136 deletions
| @@ -534,9 +534,13 @@ indentation is done using SMIE or with the old ad-hoc code. | |||
| 534 | ** Icomplete | 534 | ** Icomplete |
| 535 | 535 | ||
| 536 | +++ | 536 | +++ |
| 537 | *** New minor mode 'icomplete-vertical-mode'. | 537 | *** New minor mode 'icomplete-vertical-mode', alias 'fido-vertical-mode' |
| 538 | This mode is intended to be used with Icomplete or Fido, to display the | 538 | This mode is intended to be used with Icomplete ('M-x icomplete-mode') |
| 539 | list of completions candidates vertically instead of horizontally. | 539 | or Fido ('M-x fido-mode'), to display the list of completions |
| 540 | candidates vertically instead of horizontally. When used with | ||
| 541 | Icomplete, completions are rotated and selection kept at the top. | ||
| 542 | When used with Fido, completions scroll like a typical dropdown | ||
| 543 | widget. | ||
| 540 | 544 | ||
| 541 | --- | 545 | --- |
| 542 | ** Specific warnings can now be disabled from the warning buffer. | 546 | ** Specific warnings can now be disabled from the warning buffer. |
diff --git a/lisp/icomplete.el b/lisp/icomplete.el index 91bbb600136..f813a1776e8 100644 --- a/lisp/icomplete.el +++ b/lisp/icomplete.el | |||
| @@ -50,6 +50,8 @@ | |||
| 50 | ;;; Code: | 50 | ;;; Code: |
| 51 | 51 | ||
| 52 | (require 'rfn-eshadow) ; rfn-eshadow-overlay | 52 | (require 'rfn-eshadow) ; rfn-eshadow-overlay |
| 53 | (require 'simple) ; max-mini-window-lines | ||
| 54 | (require 'cl-lib) | ||
| 53 | 55 | ||
| 54 | (defgroup icomplete nil | 56 | (defgroup icomplete nil |
| 55 | "Show completions dynamically in minibuffer." | 57 | "Show completions dynamically in minibuffer." |
| @@ -99,6 +101,10 @@ Otherwise this should be a list of the completion tables (e.g., | |||
| 99 | "Face used by Icomplete for highlighting first match." | 101 | "Face used by Icomplete for highlighting first match." |
| 100 | :version "24.4") | 102 | :version "24.4") |
| 101 | 103 | ||
| 104 | (defface icomplete-selected-match '((t :inherit highlight)) | ||
| 105 | "Face used by `icomplete-vertical-mode' for the selected candidate." | ||
| 106 | :version "24.4") | ||
| 107 | |||
| 102 | ;;;_* User Customization variables | 108 | ;;;_* User Customization variables |
| 103 | (defcustom icomplete-prospects-height 2 | 109 | (defcustom icomplete-prospects-height 2 |
| 104 | ;; We used to compute how many lines 100 characters would take in | 110 | ;; We used to compute how many lines 100 characters would take in |
| @@ -215,6 +221,29 @@ the default otherwise." | |||
| 215 | ;; We're not at all interested in cycling here (bug#34077). | 221 | ;; We're not at all interested in cycling here (bug#34077). |
| 216 | (minibuffer-force-complete nil nil 'dont-cycle)) | 222 | (minibuffer-force-complete nil nil 'dont-cycle)) |
| 217 | 223 | ||
| 224 | ;; Apropos `icomplete-scroll', we implement "scrolling icomplete" | ||
| 225 | ;; within classic icomplete, which is "rotating", by contrast. | ||
| 226 | ;; | ||
| 227 | ;; The two variables supporing this are | ||
| 228 | ;; `icomplete--scrolled-completions' and `icomplete--scrolled-past'. | ||
| 229 | ;; They come into play when: | ||
| 230 | ;; | ||
| 231 | ;; - The user invokes commands `icomplete-forward-completions' and | ||
| 232 | ;; `icomplete-backward-completions', thus "manually" scrolling to a | ||
| 233 | ;; given position; | ||
| 234 | ;; | ||
| 235 | ;; - The user re-filters a selection that had already been manually | ||
| 236 | ;; scrolled. The system attempts to keep the previous selection | ||
| 237 | ;; stable in the face of the new filtering. This is mostly done in | ||
| 238 | ;; `icomplete--render-vertical'. | ||
| 239 | ;; | ||
| 240 | (defvar icomplete-scroll nil | ||
| 241 | "If non-nil, scroll candidates list instead of rotating it.") | ||
| 242 | (defvar icomplete--scrolled-completions nil | ||
| 243 | "If non-nil, tail of completions list manually scrolled to.") | ||
| 244 | (defvar icomplete--scrolled-past nil | ||
| 245 | "If non-nil, reverse tail of completions scrolled past.") | ||
| 246 | |||
| 218 | (defun icomplete-forward-completions () | 247 | (defun icomplete-forward-completions () |
| 219 | "Step forward completions by one entry. | 248 | "Step forward completions by one entry. |
| 220 | Second entry becomes the first and can be selected with | 249 | Second entry becomes the first and can be selected with |
| @@ -223,10 +252,14 @@ Second entry becomes the first and can be selected with | |||
| 223 | (let* ((beg (icomplete--field-beg)) | 252 | (let* ((beg (icomplete--field-beg)) |
| 224 | (end (icomplete--field-end)) | 253 | (end (icomplete--field-end)) |
| 225 | (comps (completion-all-sorted-completions beg end)) | 254 | (comps (completion-all-sorted-completions beg end)) |
| 226 | (last (last comps))) | 255 | (last (last comps))) |
| 227 | (when comps | 256 | (when (consp (cdr comps)) |
| 228 | (setcdr last (cons (car comps) (cdr last))) | 257 | (cond (icomplete-scroll |
| 229 | (completion--cache-all-sorted-completions beg end (cdr comps))))) | 258 | (push (pop comps) icomplete--scrolled-past) |
| 259 | (setq icomplete--scrolled-completions comps)) | ||
| 260 | (t | ||
| 261 | (setcdr (last comps) (cons (pop comps) (cdr last))))) | ||
| 262 | (completion--cache-all-sorted-completions beg end comps)))) | ||
| 230 | 263 | ||
| 231 | (defun icomplete-backward-completions () | 264 | (defun icomplete-backward-completions () |
| 232 | "Step backward completions by one entry. | 265 | "Step backward completions by one entry. |
| @@ -236,12 +269,16 @@ Last entry becomes the first and can be selected with | |||
| 236 | (let* ((beg (icomplete--field-beg)) | 269 | (let* ((beg (icomplete--field-beg)) |
| 237 | (end (icomplete--field-end)) | 270 | (end (icomplete--field-end)) |
| 238 | (comps (completion-all-sorted-completions beg end)) | 271 | (comps (completion-all-sorted-completions beg end)) |
| 239 | (last-but-one (last comps 2)) | 272 | last-but-one) |
| 240 | (last (cdr last-but-one))) | 273 | (cond ((and icomplete-scroll icomplete--scrolled-past) |
| 241 | (when (consp last) ; At least two elements in comps | 274 | (push (pop icomplete--scrolled-past) comps) |
| 242 | (setcdr last-but-one (cdr last)) | 275 | (setq icomplete--scrolled-completions comps)) |
| 243 | (push (car last) comps) | 276 | ((and (not icomplete-scroll) |
| 244 | (completion--cache-all-sorted-completions beg end comps)))) | 277 | (consp (cdr (setq last-but-one (last comps 2))))) |
| 278 | ;; At least two elements in comps | ||
| 279 | (push (car (cdr last-but-one)) comps) | ||
| 280 | (setcdr last-but-one (cdr (cdr last-but-one))))) | ||
| 281 | (completion--cache-all-sorted-completions beg end comps))) | ||
| 245 | 282 | ||
| 246 | ;;; Helpers for `fido-mode' (or `ido-mode' emulation) | 283 | ;;; Helpers for `fido-mode' (or `ido-mode' emulation) |
| 247 | ;;; | 284 | ;;; |
| @@ -351,6 +388,7 @@ if that doesn't produce a completion match." | |||
| 351 | (setq-local icomplete-tidy-shadowed-file-names t | 388 | (setq-local icomplete-tidy-shadowed-file-names t |
| 352 | icomplete-show-matches-on-no-input t | 389 | icomplete-show-matches-on-no-input t |
| 353 | icomplete-hide-common-prefix nil | 390 | icomplete-hide-common-prefix nil |
| 391 | icomplete-scroll (not (null icomplete-vertical-mode)) | ||
| 354 | completion-styles '(flex) | 392 | completion-styles '(flex) |
| 355 | completion-flex-nospace nil | 393 | completion-flex-nospace nil |
| 356 | completion-category-defaults nil | 394 | completion-category-defaults nil |
| @@ -449,6 +487,7 @@ Usually run by inclusion in `minibuffer-setup-hook'." | |||
| 449 | (when (and icomplete-mode (icomplete-simple-completing-p)) | 487 | (when (and icomplete-mode (icomplete-simple-completing-p)) |
| 450 | (setq-local icomplete--initial-input (icomplete--field-string)) | 488 | (setq-local icomplete--initial-input (icomplete--field-string)) |
| 451 | (setq-local completion-show-inline-help nil) | 489 | (setq-local completion-show-inline-help nil) |
| 490 | (setq icomplete--scrolled-completions nil) | ||
| 452 | (use-local-map (make-composed-keymap icomplete-minibuffer-map | 491 | (use-local-map (make-composed-keymap icomplete-minibuffer-map |
| 453 | (current-local-map))) | 492 | (current-local-map))) |
| 454 | (add-hook 'pre-command-hook #'icomplete-pre-command-hook nil t) | 493 | (add-hook 'pre-command-hook #'icomplete-pre-command-hook nil t) |
| @@ -483,6 +522,7 @@ Usually run by inclusion in `minibuffer-setup-hook'." | |||
| 483 | (defun icomplete--sorted-completions () | 522 | (defun icomplete--sorted-completions () |
| 484 | (or completion-all-sorted-completions | 523 | (or completion-all-sorted-completions |
| 485 | (cl-loop | 524 | (cl-loop |
| 525 | initially (setq icomplete--scrolled-past nil) ; Invalidate scrolled state | ||
| 486 | with beg = (icomplete--field-beg) | 526 | with beg = (icomplete--field-beg) |
| 487 | with end = (icomplete--field-end) | 527 | with end = (icomplete--field-end) |
| 488 | with all = (completion-all-sorted-completions beg end) | 528 | with all = (completion-all-sorted-completions beg end) |
| @@ -593,6 +633,8 @@ resized depends on `resize-mini-windows'." | |||
| 593 | (add-hook 'icomplete-minibuffer-setup-hook | 633 | (add-hook 'icomplete-minibuffer-setup-hook |
| 594 | #'icomplete--vertical-minibuffer-setup))) | 634 | #'icomplete--vertical-minibuffer-setup))) |
| 595 | 635 | ||
| 636 | (defalias 'fido-vertical-mode 'icomplete-vertical-mode) | ||
| 637 | |||
| 596 | 638 | ||
| 597 | 639 | ||
| 598 | 640 | ||
| @@ -659,13 +701,85 @@ See `icomplete-mode' and `minibuffer-setup-hook'." | |||
| 659 | deactivate-mark) | 701 | deactivate-mark) |
| 660 | ;; Do nothing if while-no-input was aborted. | 702 | ;; Do nothing if while-no-input was aborted. |
| 661 | (when (stringp text) | 703 | (when (stringp text) |
| 662 | (move-overlay icomplete-overlay (point) (point) (current-buffer)) | 704 | (move-overlay icomplete-overlay (point-min) (point) (current-buffer)) |
| 663 | ;; The current C cursor code doesn't know to use the overlay's | 705 | ;; The current C cursor code doesn't know to use the overlay's |
| 664 | ;; marker's stickiness to figure out whether to place the cursor | 706 | ;; marker's stickiness to figure out whether to place the cursor |
| 665 | ;; before or after the string, so let's spoon-feed it the pos. | 707 | ;; before or after the string, so let's spoon-feed it the pos. |
| 666 | (put-text-property 0 1 'cursor t text) | 708 | (put-text-property 0 1 'cursor t text) |
| 709 | (overlay-put | ||
| 710 | icomplete-overlay 'before-string | ||
| 711 | (and icomplete-scroll | ||
| 712 | (let ((past (length icomplete--scrolled-past))) | ||
| 713 | (format | ||
| 714 | "%s/%s " | ||
| 715 | (1+ past) | ||
| 716 | (+ past | ||
| 717 | (safe-length completion-all-sorted-completions)))))) | ||
| 667 | (overlay-put icomplete-overlay 'after-string text)))))))) | 718 | (overlay-put icomplete-overlay 'after-string text)))))))) |
| 668 | 719 | ||
| 720 | (cl-defun icomplete--render-vertical (comps &aux scroll-above scroll-below) | ||
| 721 | ;; Welcome to loopapalooza! | ||
| 722 | ;; | ||
| 723 | ;; First, be mindful of `icomplete-scroll' and manual scrolls. If | ||
| 724 | ;; `icomplete--scrolled-completions' and `icomplete--scrolled-past' | ||
| 725 | ;; are: | ||
| 726 | ;; | ||
| 727 | ;; - both nil, there is no manual scroll; | ||
| 728 | ;; - both non-nil, there is a healthy manual scroll the doesn't need | ||
| 729 | ;; to be readjusted (user just moved around the minibuffer, for | ||
| 730 | ;; example)l | ||
| 731 | ;; - non-nil and nil, respectively, a refiltering took place and we | ||
| 732 | ;; need attempt to readjust them to the new filtered `comps'. | ||
| 733 | (when (and icomplete-scroll | ||
| 734 | icomplete--scrolled-completions | ||
| 735 | (null icomplete--scrolled-past)) | ||
| 736 | (cl-loop with preds | ||
| 737 | for (comp . rest) on comps | ||
| 738 | when (equal comp (car icomplete--scrolled-completions)) | ||
| 739 | do | ||
| 740 | (setq icomplete--scrolled-past preds | ||
| 741 | comps (cons comp rest)) | ||
| 742 | (completion--cache-all-sorted-completions | ||
| 743 | (icomplete--field-beg) | ||
| 744 | (icomplete--field-end) | ||
| 745 | comps) | ||
| 746 | and return nil | ||
| 747 | do (push comp preds) | ||
| 748 | finally (setq icomplete--scrolled-completions nil))) | ||
| 749 | ;; Then, in this pretty ugly loop, collect completions to display | ||
| 750 | ;; above and below the selected one, considering scrolling | ||
| 751 | ;; positions. | ||
| 752 | (cl-loop with preds = icomplete--scrolled-past | ||
| 753 | with succs = (cdr comps) | ||
| 754 | with max-lines = (1- (min | ||
| 755 | icomplete-prospects-height | ||
| 756 | (truncate (max-mini-window-lines) 1))) | ||
| 757 | with max-above = (- max-lines | ||
| 758 | 1 | ||
| 759 | (cl-loop for (_ . r) on comps | ||
| 760 | repeat (truncate max-lines 2) | ||
| 761 | while (listp r) | ||
| 762 | count 1)) | ||
| 763 | repeat max-lines | ||
| 764 | for neighbour = nil | ||
| 765 | if (and preds (> max-above 0)) do | ||
| 766 | (push (setq neighbour (pop preds)) scroll-above) | ||
| 767 | (cl-decf max-above) | ||
| 768 | else if (consp succs) collect | ||
| 769 | (setq neighbour (pop succs)) into scroll-below-aux | ||
| 770 | while neighbour | ||
| 771 | finally (setq scroll-below scroll-below-aux)) | ||
| 772 | ;; Now figure out spacing and layout | ||
| 773 | ;; | ||
| 774 | (let ((selected (substring (car comps)))) | ||
| 775 | (add-face-text-property 0 (length selected) | ||
| 776 | 'icomplete-selected-match 'append selected) | ||
| 777 | (concat " " icomplete-separator | ||
| 778 | (mapconcat | ||
| 779 | #'identity | ||
| 780 | (nconc scroll-above (list selected) scroll-below) | ||
| 781 | icomplete-separator)))) | ||
| 782 | |||
| 669 | ;;;_ > icomplete-completions (name candidates predicate require-match) | 783 | ;;;_ > icomplete-completions (name candidates predicate require-match) |
| 670 | (defun icomplete-completions (name candidates predicate require-match) | 784 | (defun icomplete-completions (name candidates predicate require-match) |
| 671 | "Identify prospective candidates for minibuffer completion. | 785 | "Identify prospective candidates for minibuffer completion. |
| @@ -703,126 +817,126 @@ matches exist." | |||
| 703 | predicate)) | 817 | predicate)) |
| 704 | (md (completion--field-metadata (icomplete--field-beg))) | 818 | (md (completion--field-metadata (icomplete--field-beg))) |
| 705 | (comps (icomplete--sorted-completions)) | 819 | (comps (icomplete--sorted-completions)) |
| 706 | (last (if (consp comps) (last comps))) | ||
| 707 | (base-size (cdr last)) | ||
| 708 | (open-bracket (if require-match "(" "[")) | 820 | (open-bracket (if require-match "(" "[")) |
| 709 | (close-bracket (if require-match ")" "]"))) | 821 | (close-bracket (if require-match ")" "]"))) |
| 710 | ;; `concat'/`mapconcat' is the slow part. | 822 | ;; `concat'/`mapconcat' is the slow part. |
| 711 | (if (not (consp comps)) | 823 | (if (not (consp comps)) |
| 712 | (progn ;;(debug (format "Candidates=%S field=%S" candidates name)) | 824 | (progn ;;(debug (format "Candidates=%S field=%S" candidates name)) |
| 713 | (format " %sNo matches%s" open-bracket close-bracket)) | 825 | (format " %sNo matches%s" open-bracket close-bracket)) |
| 714 | (if last (setcdr last nil)) | 826 | (if icomplete-vertical-mode |
| 715 | (let* ((most-try | 827 | (icomplete--render-vertical comps) |
| 716 | (if (and base-size (> base-size 0)) | 828 | (let* ((last (if (consp comps) (last comps))) |
| 829 | ;; Save the "base size" encoded in `comps' then | ||
| 830 | ;; removing making `comps' a proper list. | ||
| 831 | (base-size (prog1 (cdr last) | ||
| 832 | (if last (setcdr last nil)))) | ||
| 833 | (most-try | ||
| 834 | (if (and base-size (> base-size 0)) | ||
| 835 | (completion-try-completion | ||
| 836 | name candidates predicate (length name) md) | ||
| 837 | ;; If the `comps' are 0-based, the result should be | ||
| 838 | ;; the same with `comps'. | ||
| 717 | (completion-try-completion | 839 | (completion-try-completion |
| 718 | name candidates predicate (length name) md) | 840 | name comps nil (length name) md))) |
| 719 | ;; If the `comps' are 0-based, the result should be | 841 | (most (if (consp most-try) (car most-try) |
| 720 | ;; the same with `comps'. | 842 | (if most-try (car comps) ""))) |
| 721 | (completion-try-completion | 843 | ;; Compare name and most, so we can determine if name is |
| 722 | name comps nil (length name) md))) | 844 | ;; a prefix of most, or something else. |
| 723 | (most (if (consp most-try) (car most-try) | 845 | (compare (compare-strings name nil nil |
| 724 | (if most-try (car comps) ""))) | 846 | most nil nil completion-ignore-case)) |
| 725 | ;; Compare name and most, so we can determine if name is | 847 | (ellipsis (if (char-displayable-p ?…) "…" "...")) |
| 726 | ;; a prefix of most, or something else. | 848 | (determ (unless (or (eq t compare) (eq t most-try) |
| 727 | (compare (compare-strings name nil nil | 849 | (= (setq compare (1- (abs compare))) |
| 728 | most nil nil completion-ignore-case)) | 850 | (length most))) |
| 729 | (ellipsis (if (char-displayable-p ?…) "…" "...")) | 851 | (concat open-bracket |
| 730 | (determ (unless (or (eq t compare) (eq t most-try) | 852 | (cond |
| 731 | (= (setq compare (1- (abs compare))) | 853 | ((= compare (length name)) |
| 732 | (length most))) | 854 | ;; Typical case: name is a prefix. |
| 733 | (concat open-bracket | 855 | (substring most compare)) |
| 734 | (cond | 856 | ;; Don't bother truncating if it doesn't gain |
| 735 | ((= compare (length name)) | 857 | ;; us at least 2 columns. |
| 736 | ;; Typical case: name is a prefix. | 858 | ((< compare (+ 2 (string-width ellipsis))) most) |
| 737 | (substring most compare)) | 859 | (t (concat ellipsis (substring most compare)))) |
| 738 | ;; Don't bother truncating if it doesn't gain | 860 | close-bracket))) |
| 739 | ;; us at least 2 columns. | 861 | ;;"-prospects" - more than one candidate |
| 740 | ((< compare (+ 2 (string-width ellipsis))) most) | 862 | (prospects-len (+ (string-width |
| 741 | (t (concat ellipsis (substring most compare)))) | 863 | (or determ (concat open-bracket close-bracket))) |
| 742 | close-bracket))) | 864 | (string-width icomplete-separator) |
| 743 | ;;"-prospects" - more than one candidate | 865 | (+ 2 (string-width ellipsis)) ;; take {…} into account |
| 744 | (prospects-len (+ (string-width | 866 | (string-width (buffer-string)))) |
| 745 | (or determ (concat open-bracket close-bracket))) | 867 | (prospects-max |
| 746 | (string-width icomplete-separator) | 868 | ;; Max total length to use, including the minibuffer content. |
| 747 | (+ 2 (string-width ellipsis)) ;; take {…} into account | 869 | (* (+ icomplete-prospects-height |
| 748 | (string-width (buffer-string)))) | 870 | ;; If the minibuffer content already uses up more than |
| 749 | (prospects-max | 871 | ;; one line, increase the allowable space accordingly. |
| 750 | ;; Max total length to use, including the minibuffer content. | 872 | (/ prospects-len (window-width))) |
| 751 | (* (+ icomplete-prospects-height | 873 | (window-width))) |
| 752 | ;; If the minibuffer content already uses up more than | 874 | ;; Find the common prefix among `comps'. |
| 753 | ;; one line, increase the allowable space accordingly. | 875 | ;; We can't use the optimization below because its assumptions |
| 754 | (/ prospects-len (window-width))) | 876 | ;; aren't always true, e.g. when completion-cycling (bug#10850): |
| 755 | (window-width))) | 877 | ;; (if (eq t (compare-strings (car comps) nil (length most) |
| 756 | ;; Find the common prefix among `comps'. | 878 | ;; most nil nil completion-ignore-case)) |
| 757 | ;; We can't use the optimization below because its assumptions | 879 | ;; ;; Common case. |
| 758 | ;; aren't always true, e.g. when completion-cycling (bug#10850): | 880 | ;; (length most) |
| 759 | ;; (if (eq t (compare-strings (car comps) nil (length most) | 881 | ;; Else, use try-completion. |
| 760 | ;; most nil nil completion-ignore-case)) | 882 | (prefix (when icomplete-hide-common-prefix |
| 761 | ;; ;; Common case. | 883 | (try-completion "" comps))) |
| 762 | ;; (length most) | 884 | (prefix-len |
| 763 | ;; Else, use try-completion. | 885 | (and (stringp prefix) |
| 764 | (prefix (when icomplete-hide-common-prefix | 886 | ;; Only hide the prefix if the corresponding info |
| 765 | (try-completion "" comps))) | 887 | ;; is already displayed via `most'. |
| 766 | (prefix-len | 888 | (string-prefix-p prefix most t) |
| 767 | (and (stringp prefix) | 889 | (length prefix))) ;;) |
| 768 | ;; Only hide the prefix if the corresponding info | 890 | prospects comp limit) |
| 769 | ;; is already displayed via `most'. | 891 | (prog1 |
| 770 | (string-prefix-p prefix most t) | 892 | (if (or (eq most-try t) (and (not icomplete-scroll) |
| 771 | (length prefix))) ;;) | 893 | (not (consp (cdr comps))))) |
| 772 | prospects comp limit) | 894 | (concat determ " [Matched]") |
| 773 | (if (or (eq most-try t) (not (consp (cdr comps)))) | 895 | (when (member name comps) |
| 774 | (setq prospects nil) | 896 | ;; NAME is complete but not unique. This scenario poses |
| 775 | (when (member name comps) | 897 | ;; following UI issues: |
| 776 | ;; NAME is complete but not unique. This scenario poses | 898 | ;; |
| 777 | ;; following UI issues: | 899 | ;; - When `icomplete-hide-common-prefix' is non-nil, NAME |
| 778 | ;; | 900 | ;; is stripped empty. This would make the entry |
| 779 | ;; - When `icomplete-hide-common-prefix' is non-nil, NAME | 901 | ;; inconspicuous. |
| 780 | ;; is stripped empty. This would make the entry | 902 | ;; |
| 781 | ;; inconspicuous. | 903 | ;; - Due to sorting of completions, NAME may not be the |
| 782 | ;; | 904 | ;; first of the prospects and could be hidden deep in |
| 783 | ;; - Due to sorting of completions, NAME may not be the | 905 | ;; the displayed string. |
| 784 | ;; first of the prospects and could be hidden deep in | 906 | ;; |
| 785 | ;; the displayed string. | 907 | ;; - Because of `icomplete-prospects-height' , NAME may |
| 786 | ;; | 908 | ;; not even be displayed to the user. |
| 787 | ;; - Because of `icomplete-prospects-height' , NAME may | 909 | ;; |
| 788 | ;; not even be displayed to the user. | 910 | ;; To circumvent all the above problems, provide a visual |
| 789 | ;; | 911 | ;; cue to the user via an "empty string" in the try |
| 790 | ;; To circumvent all the above problems, provide a visual | 912 | ;; completion field. |
| 791 | ;; cue to the user via an "empty string" in the try | 913 | (setq determ (concat open-bracket "" close-bracket))) |
| 792 | ;; completion field. | 914 | (while (and comps (not limit)) |
| 793 | (setq determ (concat open-bracket "" close-bracket))) | 915 | (setq comp |
| 794 | ;; Compute prospects for display. | 916 | (if prefix-len (substring (car comps) prefix-len) (car comps)) |
| 795 | (while (and comps (not limit)) | 917 | comps (cdr comps)) |
| 796 | (setq comp | 918 | (setq prospects-len |
| 797 | (if prefix-len (substring (car comps) prefix-len) (car comps)) | 919 | (+ (string-width comp) |
| 798 | comps (cdr comps)) | 920 | (string-width icomplete-separator) |
| 799 | (setq prospects-len | 921 | prospects-len)) |
| 800 | (+ (string-width comp) | 922 | (if (< prospects-len prospects-max) |
| 801 | (string-width icomplete-separator) | 923 | (push comp prospects) |
| 802 | prospects-len)) | 924 | (setq limit t))) |
| 803 | (if (< prospects-len prospects-max) | 925 | (setq prospects (nreverse prospects)) |
| 804 | (push comp prospects) | 926 | ;; Decorate first of the prospects. |
| 805 | (setq limit t)))) | 927 | (when prospects |
| 806 | (setq prospects (nreverse prospects)) | 928 | (let ((first (copy-sequence (pop prospects)))) |
| 807 | ;; Decorate first of the prospects. | 929 | (put-text-property 0 (length first) |
| 808 | (when prospects | 930 | 'face 'icomplete-first-match first) |
| 809 | (let ((first (copy-sequence (pop prospects)))) | 931 | (push first prospects))) |
| 810 | (put-text-property 0 (length first) | 932 | (concat determ |
| 811 | 'face 'icomplete-first-match first) | 933 | "{" |
| 812 | (push first prospects))) | 934 | (mapconcat 'identity prospects icomplete-separator) |
| 813 | ;; Restore the base-size info, since completion-all-sorted-completions | 935 | (concat (and limit (concat icomplete-separator ellipsis)) |
| 814 | ;; is cached. | 936 | "}"))) |
| 815 | (if last (setcdr last base-size)) | 937 | ;; Restore the base-size info, since completion-all-sorted-completions |
| 816 | (if prospects | 938 | ;; is cached. |
| 817 | (concat determ | 939 | (if last (setcdr last base-size)))))))) |
| 818 | (if icomplete-vertical-mode " \n" "{") | ||
| 819 | (mapconcat 'identity prospects (if icomplete-vertical-mode | ||
| 820 | "\n" | ||
| 821 | icomplete-separator)) | ||
| 822 | (unless icomplete-vertical-mode | ||
| 823 | (concat (and limit (concat icomplete-separator ellipsis)) | ||
| 824 | "}"))) | ||
| 825 | (concat determ " [Matched]")))))) | ||
| 826 | 940 | ||
| 827 | ;;; Iswitchb compatibility | 941 | ;;; Iswitchb compatibility |
| 828 | 942 | ||
diff --git a/lisp/simple.el b/lisp/simple.el index cdd77f74c3e..6d216f74d91 100644 --- a/lisp/simple.el +++ b/lisp/simple.el | |||
| @@ -4217,12 +4217,22 @@ impose the use of a shell (with its need to quote arguments)." | |||
| 4217 | (shell-command-on-region (point) (point) command | 4217 | (shell-command-on-region (point) (point) command |
| 4218 | output-buffer nil error-buffer))))))) | 4218 | output-buffer nil error-buffer))))))) |
| 4219 | 4219 | ||
| 4220 | (defun max-mini-window-lines (&optional frame) | ||
| 4221 | "Compute maximum number of lines for echo area in FRAME. | ||
| 4222 | As defined by `max-mini-window-height'. FRAME defaults to the | ||
| 4223 | selected frame. Result may be a floating-point number, | ||
| 4224 | i.e. include a fractional number of lines." | ||
| 4225 | (cond ((floatp max-mini-window-height) (* (frame-height frame) | ||
| 4226 | max-mini-window-height)) | ||
| 4227 | ((integerp max-mini-window-height) max-mini-window-height) | ||
| 4228 | (t 1))) | ||
| 4229 | |||
| 4220 | (defun display-message-or-buffer (message &optional buffer-name action frame) | 4230 | (defun display-message-or-buffer (message &optional buffer-name action frame) |
| 4221 | "Display MESSAGE in the echo area if possible, otherwise in a pop-up buffer. | 4231 | "Display MESSAGE in the echo area if possible, otherwise in a pop-up buffer. |
| 4222 | MESSAGE may be either a string or a buffer. | 4232 | MESSAGE may be either a string or a buffer. |
| 4223 | 4233 | ||
| 4224 | A pop-up buffer is displayed using `display-buffer' if MESSAGE is too long | 4234 | A pop-up buffer is displayed using `display-buffer' if MESSAGE is too long |
| 4225 | for maximum height of the echo area, as defined by `max-mini-window-height' | 4235 | for maximum height of the echo area, as defined by `max-mini-window-lines' |
| 4226 | if `resize-mini-windows' is non-nil. | 4236 | if `resize-mini-windows' is non-nil. |
| 4227 | 4237 | ||
| 4228 | Returns either the string shown in the echo area, or when a pop-up | 4238 | Returns either the string shown in the echo area, or when a pop-up |
| @@ -4261,14 +4271,7 @@ and are used only if a pop-up buffer is displayed." | |||
| 4261 | (cond ((= lines 0)) | 4271 | (cond ((= lines 0)) |
| 4262 | ((and (or (<= lines 1) | 4272 | ((and (or (<= lines 1) |
| 4263 | (<= lines | 4273 | (<= lines |
| 4264 | (if resize-mini-windows | 4274 | (if resize-mini-windows (max-mini-window-lines) |
| 4265 | (cond ((floatp max-mini-window-height) | ||
| 4266 | (* (frame-height) | ||
| 4267 | max-mini-window-height)) | ||
| 4268 | ((integerp max-mini-window-height) | ||
| 4269 | max-mini-window-height) | ||
| 4270 | (t | ||
| 4271 | 1)) | ||
| 4272 | 1))) | 4275 | 1))) |
| 4273 | ;; Don't use the echo area if the output buffer is | 4276 | ;; Don't use the echo area if the output buffer is |
| 4274 | ;; already displayed in the selected frame. | 4277 | ;; already displayed in the selected frame. |