]> git.eshelyaron.com Git - emacs.git/commitdiff
icomplete-vertical simplest approach feature/icomplete-vertical
authorJimmy Aguilar Mena <spacibba@aol.com>
Sat, 19 Sep 2020 08:10:01 +0000 (10:10 +0200)
committerJimmy Aguilar Mena <spacibba@aol.com>
Fri, 25 Sep 2020 03:00:46 +0000 (05:00 +0200)
* 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.

lisp/icomplete.el

index 4e546807b7f0c8cf77449ebecef73c09beb3e70b..933faa5a070fd72a320775fc97b3b6597f8d108e 100644 (file)
@@ -50,6 +50,7 @@
 ;;; Code:
 
 (require 'rfn-eshadow) ; rfn-eshadow-overlay
+(require 'cl-lib)
 
 (defgroup icomplete nil
   "Show completions dynamically in minibuffer."
@@ -139,6 +140,19 @@ icompletion is occurring."
   :group 'icomplete)
 
 
+(defvar-local icomplete--ellipsis nil
+  "Ellipsis symbol to indicate continuation.")
+
+(defvar-local icomplete--list-indicators-format nil
+  "Indicator for when multiple prospects are available.
+means that further input is required to distinguish a single one")
+
+(defvar-local icomplete--prospects nil)
+(defvar-local icomplete--match-braket nil)
+(defvar-local icomplete--prospects-max-height nil)
+(defvar-local icomplete--lines-per-candidate 0)
+
+
 ;;;_* Initialization
 
 ;;;_ + Internal Variables
@@ -437,6 +451,62 @@ Conditions are:
                (member table icomplete-with-completion-tables))))))
 
 ;;;_ > icomplete-minibuffer-setup ()
+
+(defun icomplete--vertical-prospects (prefix-len _determ comps)
+  "List of vertical completions limited."
+  ;; Max total rows to use, including the minibuffer content.
+  (let* (;; Needed for prospects-max-height-pixel
+         (single-line-height (line-pixel-height))
+         ;; in general this should be done for every line
+         (line-height (* icomplete--lines-per-candidate single-line-height))
+         (prospects-rows (+ (cdr (window-text-pixel-size))
+                            (* (cl-count ?\n icomplete--list-indicators-format) single-line-height)))
+         limit prospects comp comp-len)
+
+    (while (and comps (not limit))
+      (setq comp (substring (pop comps) prefix-len)
+            comp-len (> (length comp) 0))
+
+      (if comp-len
+           (setq prospects-rows (+ prospects-rows line-height)))
+
+      (if (< prospects-rows icomplete--prospects-max-height)
+          (if comp-len
+              (push comp prospects))
+        (push icomplete--ellipsis prospects)
+        (setq limit t)))
+    (nreverse prospects)))
+
+
+(defun icomplete--horizontal-prospects (prefix-len determ comps)
+  "List of horizontal completions limited."
+
+  (let* (;; Max total length to use, including the minibuffer content.
+         (separator-width (string-width icomplete-separator))
+         (prospects-len (+ (string-width (or determ (format icomplete--match-braket "")))
+                           (string-width icomplete-separator)
+                           (+ 2 (string-width icomplete--ellipsis)) ;; take {…} into account
+                           (string-width (buffer-string))))
+         (prospects-max-len (* (+ icomplete-prospects-height
+                                  ;; If the minibuffer content already uses up more than
+                                  ;; one line, increase the allowable space accordingly.
+                                  (/ prospects-len (window-width)))
+                               (window-width)))
+         limit prospects comp)
+
+    (while (and comps (not limit))
+      (setq comp (substring (pop comps) prefix-len))
+
+      (when (> (length comp) 0)
+          (setq prospects-len (+ prospects-len (string-width comp) separator-width)))
+
+      (if (< prospects-len prospects-max-len)
+          (push comp prospects)
+        (push icomplete--ellipsis prospects)
+        (setq limit t)))
+    (nreverse prospects)))
+
+
 (defun icomplete-minibuffer-setup ()
   "Run in minibuffer on activation to establish incremental completion.
 Usually run by inclusion in `minibuffer-setup-hook'."
@@ -446,7 +516,29 @@ Usually run by inclusion in `minibuffer-setup-hook'."
                                         (current-local-map)))
     (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)))
+    (run-hooks 'icomplete-minibuffer-setup-hook)
+
+    (setq icomplete--ellipsis (if (char-displayable-p ?…) "…" "...")
+          icomplete--lines-per-candidate (cl-count ?\n icomplete-separator))
+
+    (if (> icomplete--lines-per-candidate 0)
+        (setq-local icomplete--list-indicators-format " \n%s"
+                    icomplete--prospects 'icomplete--vertical-prospects
+                    icomplete--prospects-max-height
+                    (let ((minibuffer-parameter (frame-parameter nil 'minibuffer)))
+                      (min (cond
+                            ((eq minibuffer-parameter t)
+                             (if (floatp max-mini-window-height)
+                                 (* max-mini-window-height (frame-pixel-height))
+                               (* max-mini-window-height (frame-char-height))))
+                            ;; TODO: minibuffer-parameter can be nil, what to do then?.
+                            ((eq minibuffer-parameter 'only)
+                             (frame-pixel-height)))
+                           (* (+ 2 icomplete-prospects-height) (line-pixel-height)))))
+
+      (setq-local icomplete--list-indicators-format "{%s}"
+                  icomplete--prospects 'icomplete--horizontal-prospects))))
+
 
 (defvar icomplete--in-region-buffer nil)
 
@@ -639,8 +731,6 @@ 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.
 
 If there are multiple possibilities, `icomplete-separator' separates them.
 
@@ -665,13 +755,13 @@ matches exist."
         (md (completion--field-metadata (icomplete--field-beg)))
         (comps (icomplete--sorted-completions))
          (last (if (consp comps) (last comps)))
-         (base-size (cdr last))
-         (open-bracket (if require-match "(" "["))
-         (close-bracket (if require-match ")" "]")))
+         (base-size (cdr last)))
+
+    (setq-local icomplete--match-braket (if require-match "(%s)" "[%s]"))
     ;; `concat'/`mapconcat' is the slow part.
     (if (not (consp comps))
        (progn ;;(debug (format "Candidates=%S field=%S" candidates name))
-         (format " %sNo matches%s" open-bracket close-bracket))
+         (format icomplete--match-braket "No matches"))
       (if last (setcdr last nil))
       (let* ((most-try
               (if (and base-size (> base-size 0))
@@ -687,33 +777,18 @@ matches exist."
              ;; 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)))
-                      (concat open-bracket
+                      (format icomplete--match-braket
                               (cond
                                ((= compare (length name))
                                  ;; Typical case: name is a prefix.
                                 (substring most compare))
                                 ;; Don't bother truncating if it doesn't gain
                                 ;; us at least 2 columns.
-                               ((< compare (+ 2 (string-width ellipsis))) most)
-                               (t (concat ellipsis (substring most compare))))
-                              close-bracket)))
-            ;;"-prospects" - more than one candidate
-            (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
-                    ;; If the minibuffer content already uses up more than
-                    ;; one line, increase the allowable space accordingly.
-                    (/ prospects-len (window-width)))
-                 (window-width)))
+                               ((< compare (+ 2 (string-width icomplete--ellipsis))) most)
+                               (t (concat icomplete--ellipsis (substring most compare)))))))
              ;; 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):
@@ -725,12 +800,13 @@ matches exist."
             (prefix (when icomplete-hide-common-prefix
                       (try-completion "" comps)))
              (prefix-len
-             (and (stringp prefix)
+              (and icomplete-hide-common-prefix
+                   (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)
+                   (length prefix)))
+            prospects)
        (if (or (eq most-try t) (not (consp (cdr comps))))
            (setq prospects nil)
          (when (member name comps)
@@ -751,20 +827,11 @@ matches exist."
            ;; 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)))
+           (setq determ (format icomplete--match-braket "")))
          ;; Compute prospects for display.
-         (while (and comps (not limit))
-           (setq comp
-                 (if prefix-len (substring (car comps) prefix-len) (car comps))
-                 comps (cdr comps))
-           (setq prospects-len
-                  (+ (string-width comp)
-                    (string-width icomplete-separator)
-                    prospects-len))
-           (if (< prospects-len prospects-max)
-               (push comp prospects)
-             (setq limit t))))
-       (setq prospects (nreverse prospects))
+          (setq prospects
+                (funcall icomplete--prospects prefix-len determ comps)))
+
        ;; Decorate first of the prospects.
        (when prospects
          (let ((first (copy-sequence (pop prospects))))
@@ -776,10 +843,8 @@ matches exist."
         (if last (setcdr last base-size))
        (if prospects
            (concat determ
-                   "{"
-                   (mapconcat 'identity prospects icomplete-separator)
-                   (and limit (concat icomplete-separator ellipsis))
-                   "}")
+                    (format icomplete--list-indicators-format
+                            (mapconcat 'identity prospects icomplete-separator)))
          (concat determ " [Matched]"))))))
 
 ;;; Iswitchb compatibility