diff options
| author | Jimmy Aguilar Mena | 2020-09-19 10:10:01 +0200 |
|---|---|---|
| committer | Jimmy Aguilar Mena | 2020-09-25 05:00:46 +0200 |
| commit | 95e298e03181ad3c96f2969911d90d70048fca0c (patch) | |
| tree | fd652f7ea0cabafc790fb265ab161fbeea0e661a | |
| parent | 976b8464fb3d33a83432053d7f907cb763580cea (diff) | |
| download | emacs-feature/icomplete-vertical.tar.gz emacs-feature/icomplete-vertical.zip | |
icomplete-vertical simplest approachfeature/icomplete-vertical
* lisp/icomplete.el (icomplete--vertical-prospects) : New functions to
assert format and correct number of candidates in vertical format.
(icomplete--horizontal-prospects) : New functions to assert format and
correct number of candidates in horizontal format.
(icomplete-minibuffer-setup-hook) : Conditionally initialize the
variables for vertical format.
(icomplete-completions) : Simplify to separate some calculations
unneeded in vertical format. Moved part of its code to
icomplete--horizontal-prospects.
| -rw-r--r-- | lisp/icomplete.el | 155 |
1 files changed, 110 insertions, 45 deletions
diff --git a/lisp/icomplete.el b/lisp/icomplete.el index 4e546807b7f..933faa5a070 100644 --- a/lisp/icomplete.el +++ b/lisp/icomplete.el | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | ;;; Code: | 50 | ;;; Code: |
| 51 | 51 | ||
| 52 | (require 'rfn-eshadow) ; rfn-eshadow-overlay | 52 | (require 'rfn-eshadow) ; rfn-eshadow-overlay |
| 53 | (require 'cl-lib) | ||
| 53 | 54 | ||
| 54 | (defgroup icomplete nil | 55 | (defgroup icomplete nil |
| 55 | "Show completions dynamically in minibuffer." | 56 | "Show completions dynamically in minibuffer." |
| @@ -139,6 +140,19 @@ icompletion is occurring." | |||
| 139 | :group 'icomplete) | 140 | :group 'icomplete) |
| 140 | 141 | ||
| 141 | 142 | ||
| 143 | (defvar-local icomplete--ellipsis nil | ||
| 144 | "Ellipsis symbol to indicate continuation.") | ||
| 145 | |||
| 146 | (defvar-local icomplete--list-indicators-format nil | ||
| 147 | "Indicator for when multiple prospects are available. | ||
| 148 | means that further input is required to distinguish a single one") | ||
| 149 | |||
| 150 | (defvar-local icomplete--prospects nil) | ||
| 151 | (defvar-local icomplete--match-braket nil) | ||
| 152 | (defvar-local icomplete--prospects-max-height nil) | ||
| 153 | (defvar-local icomplete--lines-per-candidate 0) | ||
| 154 | |||
| 155 | |||
| 142 | ;;;_* Initialization | 156 | ;;;_* Initialization |
| 143 | 157 | ||
| 144 | ;;;_ + Internal Variables | 158 | ;;;_ + Internal Variables |
| @@ -437,6 +451,62 @@ Conditions are: | |||
| 437 | (member table icomplete-with-completion-tables)))))) | 451 | (member table icomplete-with-completion-tables)))))) |
| 438 | 452 | ||
| 439 | ;;;_ > icomplete-minibuffer-setup () | 453 | ;;;_ > icomplete-minibuffer-setup () |
| 454 | |||
| 455 | (defun icomplete--vertical-prospects (prefix-len _determ comps) | ||
| 456 | "List of vertical completions limited." | ||
| 457 | ;; Max total rows to use, including the minibuffer content. | ||
| 458 | (let* (;; Needed for prospects-max-height-pixel | ||
| 459 | (single-line-height (line-pixel-height)) | ||
| 460 | ;; in general this should be done for every line | ||
| 461 | (line-height (* icomplete--lines-per-candidate single-line-height)) | ||
| 462 | (prospects-rows (+ (cdr (window-text-pixel-size)) | ||
| 463 | (* (cl-count ?\n icomplete--list-indicators-format) single-line-height))) | ||
| 464 | limit prospects comp comp-len) | ||
| 465 | |||
| 466 | (while (and comps (not limit)) | ||
| 467 | (setq comp (substring (pop comps) prefix-len) | ||
| 468 | comp-len (> (length comp) 0)) | ||
| 469 | |||
| 470 | (if comp-len | ||
| 471 | (setq prospects-rows (+ prospects-rows line-height))) | ||
| 472 | |||
| 473 | (if (< prospects-rows icomplete--prospects-max-height) | ||
| 474 | (if comp-len | ||
| 475 | (push comp prospects)) | ||
| 476 | (push icomplete--ellipsis prospects) | ||
| 477 | (setq limit t))) | ||
| 478 | (nreverse prospects))) | ||
| 479 | |||
| 480 | |||
| 481 | (defun icomplete--horizontal-prospects (prefix-len determ comps) | ||
| 482 | "List of horizontal completions limited." | ||
| 483 | |||
| 484 | (let* (;; Max total length to use, including the minibuffer content. | ||
| 485 | (separator-width (string-width icomplete-separator)) | ||
| 486 | (prospects-len (+ (string-width (or determ (format icomplete--match-braket ""))) | ||
| 487 | (string-width icomplete-separator) | ||
| 488 | (+ 2 (string-width icomplete--ellipsis)) ;; take {…} into account | ||
| 489 | (string-width (buffer-string)))) | ||
| 490 | (prospects-max-len (* (+ icomplete-prospects-height | ||
| 491 | ;; If the minibuffer content already uses up more than | ||
| 492 | ;; one line, increase the allowable space accordingly. | ||
| 493 | (/ prospects-len (window-width))) | ||
| 494 | (window-width))) | ||
| 495 | limit prospects comp) | ||
| 496 | |||
| 497 | (while (and comps (not limit)) | ||
| 498 | (setq comp (substring (pop comps) prefix-len)) | ||
| 499 | |||
| 500 | (when (> (length comp) 0) | ||
| 501 | (setq prospects-len (+ prospects-len (string-width comp) separator-width))) | ||
| 502 | |||
| 503 | (if (< prospects-len prospects-max-len) | ||
| 504 | (push comp prospects) | ||
| 505 | (push icomplete--ellipsis prospects) | ||
| 506 | (setq limit t))) | ||
| 507 | (nreverse prospects))) | ||
| 508 | |||
| 509 | |||
| 440 | (defun icomplete-minibuffer-setup () | 510 | (defun icomplete-minibuffer-setup () |
| 441 | "Run in minibuffer on activation to establish incremental completion. | 511 | "Run in minibuffer on activation to establish incremental completion. |
| 442 | Usually run by inclusion in `minibuffer-setup-hook'." | 512 | Usually run by inclusion in `minibuffer-setup-hook'." |
| @@ -446,7 +516,29 @@ Usually run by inclusion in `minibuffer-setup-hook'." | |||
| 446 | (current-local-map))) | 516 | (current-local-map))) |
| 447 | (add-hook 'pre-command-hook #'icomplete-pre-command-hook nil t) | 517 | (add-hook 'pre-command-hook #'icomplete-pre-command-hook nil t) |
| 448 | (add-hook 'post-command-hook #'icomplete-post-command-hook nil t) | 518 | (add-hook 'post-command-hook #'icomplete-post-command-hook nil t) |
| 449 | (run-hooks 'icomplete-minibuffer-setup-hook))) | 519 | (run-hooks 'icomplete-minibuffer-setup-hook) |
| 520 | |||
| 521 | (setq icomplete--ellipsis (if (char-displayable-p ?…) "…" "...") | ||
| 522 | icomplete--lines-per-candidate (cl-count ?\n icomplete-separator)) | ||
| 523 | |||
| 524 | (if (> icomplete--lines-per-candidate 0) | ||
| 525 | (setq-local icomplete--list-indicators-format " \n%s" | ||
| 526 | icomplete--prospects 'icomplete--vertical-prospects | ||
| 527 | icomplete--prospects-max-height | ||
| 528 | (let ((minibuffer-parameter (frame-parameter nil 'minibuffer))) | ||
| 529 | (min (cond | ||
| 530 | ((eq minibuffer-parameter t) | ||
| 531 | (if (floatp max-mini-window-height) | ||
| 532 | (* max-mini-window-height (frame-pixel-height)) | ||
| 533 | (* max-mini-window-height (frame-char-height)))) | ||
| 534 | ;; TODO: minibuffer-parameter can be nil, what to do then?. | ||
| 535 | ((eq minibuffer-parameter 'only) | ||
| 536 | (frame-pixel-height))) | ||
| 537 | (* (+ 2 icomplete-prospects-height) (line-pixel-height))))) | ||
| 538 | |||
| 539 | (setq-local icomplete--list-indicators-format "{%s}" | ||
| 540 | icomplete--prospects 'icomplete--horizontal-prospects)))) | ||
| 541 | |||
| 450 | 542 | ||
| 451 | (defvar icomplete--in-region-buffer nil) | 543 | (defvar icomplete--in-region-buffer nil) |
| 452 | 544 | ||
| @@ -639,8 +731,6 @@ one of (), [], or {} pairs. The choice of brackets is as follows: | |||
| 639 | 731 | ||
| 640 | (...) - a single prospect is identified and matching is enforced, | 732 | (...) - a single prospect is identified and matching is enforced, |
| 641 | [...] - a single prospect is identified but matching is optional, or | 733 | [...] - a single prospect is identified but matching is optional, or |
| 642 | {...} - multiple prospects, separated by commas, are indicated, and | ||
| 643 | further input is required to distinguish a single one. | ||
| 644 | 734 | ||
| 645 | If there are multiple possibilities, `icomplete-separator' separates them. | 735 | If there are multiple possibilities, `icomplete-separator' separates them. |
| 646 | 736 | ||
| @@ -665,13 +755,13 @@ matches exist." | |||
| 665 | (md (completion--field-metadata (icomplete--field-beg))) | 755 | (md (completion--field-metadata (icomplete--field-beg))) |
| 666 | (comps (icomplete--sorted-completions)) | 756 | (comps (icomplete--sorted-completions)) |
| 667 | (last (if (consp comps) (last comps))) | 757 | (last (if (consp comps) (last comps))) |
| 668 | (base-size (cdr last)) | 758 | (base-size (cdr last))) |
| 669 | (open-bracket (if require-match "(" "[")) | 759 | |
| 670 | (close-bracket (if require-match ")" "]"))) | 760 | (setq-local icomplete--match-braket (if require-match "(%s)" "[%s]")) |
| 671 | ;; `concat'/`mapconcat' is the slow part. | 761 | ;; `concat'/`mapconcat' is the slow part. |
| 672 | (if (not (consp comps)) | 762 | (if (not (consp comps)) |
| 673 | (progn ;;(debug (format "Candidates=%S field=%S" candidates name)) | 763 | (progn ;;(debug (format "Candidates=%S field=%S" candidates name)) |
| 674 | (format " %sNo matches%s" open-bracket close-bracket)) | 764 | (format icomplete--match-braket "No matches")) |
| 675 | (if last (setcdr last nil)) | 765 | (if last (setcdr last nil)) |
| 676 | (let* ((most-try | 766 | (let* ((most-try |
| 677 | (if (and base-size (> base-size 0)) | 767 | (if (and base-size (> base-size 0)) |
| @@ -687,33 +777,18 @@ matches exist." | |||
| 687 | ;; a prefix of most, or something else. | 777 | ;; a prefix of most, or something else. |
| 688 | (compare (compare-strings name nil nil | 778 | (compare (compare-strings name nil nil |
| 689 | most nil nil completion-ignore-case)) | 779 | most nil nil completion-ignore-case)) |
| 690 | (ellipsis (if (char-displayable-p ?…) "…" "...")) | ||
| 691 | (determ (unless (or (eq t compare) (eq t most-try) | 780 | (determ (unless (or (eq t compare) (eq t most-try) |
| 692 | (= (setq compare (1- (abs compare))) | 781 | (= (setq compare (1- (abs compare))) |
| 693 | (length most))) | 782 | (length most))) |
| 694 | (concat open-bracket | 783 | (format icomplete--match-braket |
| 695 | (cond | 784 | (cond |
| 696 | ((= compare (length name)) | 785 | ((= compare (length name)) |
| 697 | ;; Typical case: name is a prefix. | 786 | ;; Typical case: name is a prefix. |
| 698 | (substring most compare)) | 787 | (substring most compare)) |
| 699 | ;; Don't bother truncating if it doesn't gain | 788 | ;; Don't bother truncating if it doesn't gain |
| 700 | ;; us at least 2 columns. | 789 | ;; us at least 2 columns. |
| 701 | ((< compare (+ 2 (string-width ellipsis))) most) | 790 | ((< compare (+ 2 (string-width icomplete--ellipsis))) most) |
| 702 | (t (concat ellipsis (substring most compare)))) | 791 | (t (concat icomplete--ellipsis (substring most compare))))))) |
| 703 | close-bracket))) | ||
| 704 | ;;"-prospects" - more than one candidate | ||
| 705 | (prospects-len (+ (string-width | ||
| 706 | (or determ (concat open-bracket close-bracket))) | ||
| 707 | (string-width icomplete-separator) | ||
| 708 | (+ 2 (string-width ellipsis)) ;; take {…} into account | ||
| 709 | (string-width (buffer-string)))) | ||
| 710 | (prospects-max | ||
| 711 | ;; Max total length to use, including the minibuffer content. | ||
| 712 | (* (+ icomplete-prospects-height | ||
| 713 | ;; If the minibuffer content already uses up more than | ||
| 714 | ;; one line, increase the allowable space accordingly. | ||
| 715 | (/ prospects-len (window-width))) | ||
| 716 | (window-width))) | ||
| 717 | ;; Find the common prefix among `comps'. | 792 | ;; Find the common prefix among `comps'. |
| 718 | ;; We can't use the optimization below because its assumptions | 793 | ;; We can't use the optimization below because its assumptions |
| 719 | ;; aren't always true, e.g. when completion-cycling (bug#10850): | 794 | ;; aren't always true, e.g. when completion-cycling (bug#10850): |
| @@ -725,12 +800,13 @@ matches exist." | |||
| 725 | (prefix (when icomplete-hide-common-prefix | 800 | (prefix (when icomplete-hide-common-prefix |
| 726 | (try-completion "" comps))) | 801 | (try-completion "" comps))) |
| 727 | (prefix-len | 802 | (prefix-len |
| 728 | (and (stringp prefix) | 803 | (and icomplete-hide-common-prefix |
| 804 | (stringp prefix) | ||
| 729 | ;; Only hide the prefix if the corresponding info | 805 | ;; Only hide the prefix if the corresponding info |
| 730 | ;; is already displayed via `most'. | 806 | ;; is already displayed via `most'. |
| 731 | (string-prefix-p prefix most t) | 807 | (string-prefix-p prefix most t) |
| 732 | (length prefix))) ;;) | 808 | (length prefix))) |
| 733 | prospects comp limit) | 809 | prospects) |
| 734 | (if (or (eq most-try t) (not (consp (cdr comps)))) | 810 | (if (or (eq most-try t) (not (consp (cdr comps)))) |
| 735 | (setq prospects nil) | 811 | (setq prospects nil) |
| 736 | (when (member name comps) | 812 | (when (member name comps) |
| @@ -751,20 +827,11 @@ matches exist." | |||
| 751 | ;; To circumvent all the above problems, provide a visual | 827 | ;; To circumvent all the above problems, provide a visual |
| 752 | ;; cue to the user via an "empty string" in the try | 828 | ;; cue to the user via an "empty string" in the try |
| 753 | ;; completion field. | 829 | ;; completion field. |
| 754 | (setq determ (concat open-bracket "" close-bracket))) | 830 | (setq determ (format icomplete--match-braket ""))) |
| 755 | ;; Compute prospects for display. | 831 | ;; Compute prospects for display. |
| 756 | (while (and comps (not limit)) | 832 | (setq prospects |
| 757 | (setq comp | 833 | (funcall icomplete--prospects prefix-len determ comps))) |
| 758 | (if prefix-len (substring (car comps) prefix-len) (car comps)) | 834 | |
| 759 | comps (cdr comps)) | ||
| 760 | (setq prospects-len | ||
| 761 | (+ (string-width comp) | ||
| 762 | (string-width icomplete-separator) | ||
| 763 | prospects-len)) | ||
| 764 | (if (< prospects-len prospects-max) | ||
| 765 | (push comp prospects) | ||
| 766 | (setq limit t)))) | ||
| 767 | (setq prospects (nreverse prospects)) | ||
| 768 | ;; Decorate first of the prospects. | 835 | ;; Decorate first of the prospects. |
| 769 | (when prospects | 836 | (when prospects |
| 770 | (let ((first (copy-sequence (pop prospects)))) | 837 | (let ((first (copy-sequence (pop prospects)))) |
| @@ -776,10 +843,8 @@ matches exist." | |||
| 776 | (if last (setcdr last base-size)) | 843 | (if last (setcdr last base-size)) |
| 777 | (if prospects | 844 | (if prospects |
| 778 | (concat determ | 845 | (concat determ |
| 779 | "{" | 846 | (format icomplete--list-indicators-format |
| 780 | (mapconcat 'identity prospects icomplete-separator) | 847 | (mapconcat 'identity prospects icomplete-separator))) |
| 781 | (and limit (concat icomplete-separator ellipsis)) | ||
| 782 | "}") | ||
| 783 | (concat determ " [Matched]")))))) | 848 | (concat determ " [Matched]")))))) |
| 784 | 849 | ||
| 785 | ;;; Iswitchb compatibility | 850 | ;;; Iswitchb compatibility |