Browse Source

Make ido-cr+ handle dynamic completion tables

The idea for this implementation was copied from ivy-mode:
https://github.com/abo-abo/swiper

Note that this doesn't mean ido-cr+ can completely replace
completing-read-default everywhere. Things like tmm which implement
custom display and keybindings on top of completing-read will still
break it. Ido-ubiquitous may still be required as a gatekeeper for
these cases.

This now makes ido-describe-fns completely obsolete, so it has been
deleted.
Ryan C. Thompson 8 years ago
parent
commit
d7feee9079
2 changed files with 48 additions and 108 deletions
  1. 48 16
      ido-completing-read+.el
  2. 0 92
      ido-describe-fns.el

+ 48 - 16
ido-completing-read+.el

@@ -78,12 +78,19 @@ the other command.
 This is set to -1 by default, since `(minibuffer-depth)' should
 never return this value.")
 
-(defvar ido-cr+-force-on-functional-collection nil
-  "If non-nil, the next call to `ido-completing-read+' will operate on functional collections.
+(defvar ido-cr+-assume-static-collection nil
+  "If non-nil, ido-cr+ will assume that the collection is static.
 
-This is not meant to be set permanently, but rather let-bound
-before calling `ido-completing-read+' under controlled
-circumstances.")
+This is used to avoid unnecessary work in the case where the
+collection is a function, since a function collection could
+potentially change the set of completion candidates
+dynamically.")
+
+(defvar ido-cr+-dynamic-collection nil
+  "Stores the collection argument if it is a function.
+
+This allows ido-cr+ to update the set of completion candidates
+dynamically.")
 
 (defvar ido-cr+-no-default-action 'prepend-empty-string
   "Controls the behavior of ido-cr+ when DEF is nil and REQUIRE-MATCH is non-nil.
@@ -216,7 +223,15 @@ completion for them."
         ;; fallback
         (ido-cr+-orig-completing-read-args
          (list prompt collection predicate require-match
-               initial-input hist def inherit-input-method)))
+               initial-input hist def inherit-input-method))
+        ;; Make a private copy of this variable
+        (ido-cr+-assume-static-collection ido-cr+-assume-static-collection)
+        ;; If collection is a function, save it for later, unless
+        ;; instructed not to
+        (ido-cr+-dynamic-collection
+         (when (and (not ido-cr+-assume-static-collection)
+                    (functionp collection))
+           collection)))
     (condition-case sig
         (progn
           ;; Check a bunch of fallback conditions
@@ -226,18 +241,12 @@ completion for them."
                     '("ido cannot handle non-nil INHERIT-INPUT-METHOD")))
            ((bound-and-true-p completion-extra-properties)
             (signal 'ido-cr+-fallback
-                    '("ido cannot handle non-nil `completion-extra-properties'")))
-           ((and (functionp collection)
-                 (not ido-cr+-force-on-functional-collection))
-            (signal 'ido-cr+-fallback
-                    '("ido cannot handle COLLECTION being a function (but see `ido-cr+-force-on-functional-collection')"))))
-
-          ;; Expand all possible completions. (Apologies to everyone
-          ;; who worked so hard to make lazy collections work; ido
-          ;; doesn't know how to handle those.)
+                    '("ido cannot handle non-nil `completion-extra-properties'"))))
+          ;; Expand all currently-known completions.
           (setq collection (all-completions "" collection predicate))
           ;; No point in using ido unless there's a collection
-          (when (= (length collection) 0)
+          (when (and (= (length collection) 0)
+                     (not ido-cr+-dynamic-collection))
             (signal 'ido-cr+-fallback '("ido is not needed for an empty collection")))
           ;; Check for excessively large collection
           (when (and ido-cr+-max-items
@@ -382,6 +391,29 @@ sets up C-j to be equivalent to TAB in the same situation."
         (ido-complete))
     ad-do-it))
 
+(defadvice ido-exhibit (before ido-cr+-update-dynamic-collection activate)
+  "Maybe update the set of completions when ido-text changes."
+  (when ido-cr+-dynamic-collection
+    (let ((prev-ido-text ido-text)
+          (current-ido-text (buffer-substring-no-properties (minibuffer-prompt-end) (point-max))))
+      (when (not (string= prev-ido-text current-ido-text))
+        (let ((current-match (car ido-matches))
+              (def (nth 6 ido-cr+-orig-completing-read-args))
+              (predicate (nth 2 ido-cr+-orig-completing-read-args)))
+          (setq ido-cur-list
+                (all-completions current-ido-text
+                                 ido-cr+-dynamic-collection
+                                 predicate))
+          (unless (listp def)
+            (setq def (list def)))
+          (when def
+            (setq ido-cur-list
+                  (append def (cl-set-difference ido-cur-list def
+                                                 :test #'equal))))
+          (when (and current-match (member current-match ido-cur-list))
+            (setq ido-cur-list (ido-chop ido-cur-list current-match))))
+        (ido-cr+--debug-message "Updated completion candidates for dynamic collection because `ido-text' changed from %S to %S. `ido-cur-list' now has %s elements" prev-ido-text current-ido-text (length ido-cur-list))))))
+
 ;; Interoperation with minibuffer-electric-default-mode: only show the
 ;; default when the input is empty and the empty string is the selected
 (defadvice minibuf-eldef-update-minibuffer (around ido-cr+-compat activate)

+ 0 - 92
ido-describe-fns.el

@@ -1,92 +0,0 @@
-;;; ido-describe-fns.el ---  -*- lexical-binding: t -*-
-
-;; Copyright (C) 2017 Ryan C. Thompson
-
-;; Filename: ido-describe-fns.el
-;; Author: Ryan C. Thompson
-;; Created: Tue May 16 18:23:13 2017 (-0400)
-;; Version: 4.0
-;; Package-Requires: ((emacs "26") (ido-completing-read+ 3.17) (ido-ubiquitous 3.17))
-;; URL: https://github.com/DarwinAwardWinner/ido-ubiquitous
-;; Keywords: ido, completion, convenience
-
-;; This file is NOT part of GNU Emacs.
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 
-;;; Commentary: 
-
-;; This package is an extension for ido-ubiquitous that implements ido
-;; completion for the new implementation of the `describe-*' family of
-;; commands. In Emacs 26 and above, these commands no longer work with
-;; ido-ubiquitous because they now use a function-based collection
-;; argument to implement auto-loading of the file corresponding to the
-;; prefix you entered in order to offer completions of symbols from
-;; that file.
-
-;; Note that there is no separate mode to enable. If
-;; `ido-ubiquitous-mode' is already enabled, then simply loading this
-;; package will enable it as well.
-
-;; This package has no effect in Emacs versions earlier than 26, so it
-;; is safe to install it unconditionally in an Emacs config shared by
-;; multiple Emacs versions.
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 
-;; This program is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or (at
-;; your option) any later version.
-;; 
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;; General Public License for more details.
-;; 
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
-;; 
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; 
-;;; Code:
-
-(defconst ido-describe-fns-version "4.0"
-  "Currently running version of ido-describe-fns.
-
-Note that when you update ido-describe-fns, this variable may not
-be updated until you restart Emacs.")
-
-(require 'ido)
-(require 'ido-completing-read+)
-(require 'ido-ubiquitous)
-
-(defun ido-descfns-maybe-load-prefixes (string)
-  "Load any files needed to complete the current input.
-
-This function auto-loads new files in the same way as
-`help--symbol-completion-table', but without doing any
-completion.
-
-Returns non-nil if any new files were loaded."
-  (when (bound-and-true-p help-definition-prefixes)
-    (let* ((old-load-history load-history)
-           (prefixes (radix-tree-prefixes (help-definition-prefixes) string)))
-      (help--load-prefixes prefixes)
-      (not (eq load-history old-load-history)))))
-
-;; `ido-exhibit' is the ido post-command hook
-(defadvice ido-exhibit (before ido-descfns activate)
-  "Maybe load new files and update possible ido completions.
-
-Has no effect unless `ido-descfns-enable-this-call' is non-nil."
-  (when (and (ido-ubiquitous-active)
-             (ido-descfns-maybe-load-prefixes ido-text))
-    (with-no-warnings
-      (setq ido-cur-list
-            (all-completions "" obarray (nth 2 ido-cr+-orig-completing-read-args)))
-      (ido-ubiquitous--debug-message "ido-describe-fns loaded new files. `ido-cur-list' now has %i items" (length ido-cur-list)))))
-
-(provide 'ido-describe-fns)
-
-;;; ido-describe-fns.el ends here