New upstream version 4.5
Lev Lamberov
6 years ago
0 | language: generic | |
1 | ||
2 | env: | |
3 | matrix: | |
4 | - EMACS_VERSION=emacs-24.4 | |
5 | - EMACS_VERSION=emacs-24.5 | |
6 | - EMACS_VERSION=emacs-25.1 | |
7 | - EMACS_VERSION=emacs-25.2 | |
8 | - EMACS_VERSION=emacs-git-snapshot | |
9 | - EMACS_VERSION=remacs-git-snapshot | |
10 | ||
11 | matrix: | |
12 | allow_failures: | |
13 | - env: EMACS_VERSION=remacs-git-snapshot | |
14 | ||
15 | before_script: | |
16 | # Install evm | |
17 | - git clone https://github.com/rejeep/evm.git ~/.evm | |
18 | - export PATH="$HOME/.evm/bin:$PATH" | |
19 | - evm config path /tmp | |
20 | - evm list | |
21 | # use this version of emacs for tests | |
22 | - evm install "${EMACS_VERSION}-travis" --use --skip | |
23 | - evm list | |
24 | - emacs --version | |
25 | # Install cask | |
26 | - curl -fsSkL https://raw.github.com/cask/cask/master/go | python | |
27 | - export PATH="$HOME/.cask/bin:$PATH" | |
28 | # Install elisp dependencies | |
29 | - cask install | |
30 | ||
31 | script: | |
32 | cask exec buttercup -L . |
0 | 0 | ;; -*- mode: emacs-lisp -*- |
1 | 1 | |
2 | (source gnu) | |
2 | 3 | (source melpa) |
3 | 4 | |
4 | (package "ido-ubiquitous" "3.8" "Use ido (nearly) everywhere.") | |
5 | (package-file "ido-completing-read+.el") | |
6 | ||
7 | (depends-on "s") | |
8 | (depends-on "memoize" "1.1") | |
5 | 9 | |
6 | 10 | (development |
7 | (depends-on "f") | |
8 | (depends-on "ert-runner")) | |
11 | (depends-on "with-simulated-input" | |
12 | :git "https://github.com/DarwinAwardWinner/with-simulated-input.git" | |
13 | :files ("*.el")) | |
14 | (depends-on "buttercup" | |
15 | :git "https://github.com/DarwinAwardWinner/emacs-buttercup.git" | |
16 | :branch "expect-closures" | |
17 | :files ("*.el" | |
18 | ("bin" "bin/*")))) |
0 | 2017-08-13 Ryan C. Thompson <rct@thompsonclan.org> | |
1 | ||
2 | * ido-completing-read+.el (ido-cr+-apply-restrictions): Make | |
3 | "ido-restrict-to-matches" work with dynamic completion tables. | |
4 | ||
5 | (ido-cr+-update-dynamic-collection): Make behavior on dynamic | |
6 | completion tables more deterministic. The set of offered | |
7 | completions now only depends on the current input, not the precise | |
8 | sequence of insertions and deletions the user used to end up | |
9 | there. ido-completing-read+ now depends on the memoize package. | |
10 | ||
11 | 2017-08-07 Ryan C. Thompson <rct@thompsonclan.org> | |
12 | ||
13 | * ido-completing-read+.el: Declare missing dependency on "s" | |
14 | pacakge. | |
15 | ||
16 | (ido-completing-read+): Allow DEF to be a string (or list of | |
17 | strings). | |
18 | ||
19 | (ido-cr+-nil-def-alternate-behavior-list): Support commands that | |
20 | behave badly when "require-match" is non-nil and "def" is nil. | |
21 | ||
22 | (ido-select-text@ido-cr+-fix-require-match): If the collection is | |
23 | dynamic, use "try-completion" as an alternative way to check for a | |
24 | match. | |
25 | ||
26 | 2017-07-24 Ryan C. Thompson <rct@thompsonclan.org> | |
27 | ||
28 | * ido-completing-read+.el: Further improvements to handling of | |
29 | dynamic completion tables. Among other things, flex matching is | |
30 | now supported for dynamic tables, and idle timers are used to | |
31 | avoid recalculating the list of completions between every | |
32 | keystroke. | |
33 | ||
34 | 2017-07-08 Ryan C. Thompson <rct@thompsonclan.org> | |
35 | ||
36 | * ido-completing-read+.el: Internal change: switch to the new | |
37 | "nadvice" system for all function advice. | |
38 | ||
39 | 2017-07-05 Ryan C. Thompson <rct@thompsonclan.org> | |
40 | ||
41 | * ido-completing-read+.el (ido-completing-read+): Massive | |
42 | refactor. The "overrides" system has been completely reworked. | |
43 | There is no longer a distinction between "old" and "new" default | |
44 | styles; commands and functions are no longer treated differently; | |
45 | and ido-cr+ is now enabled for dynamic completion tables. Users | |
46 | should read the FAQ, which explains the minor user-visible | |
47 | changes. | |
48 | ||
49 | * ido-ubiquitous.el: Refactor entire package into ido-cr+. The | |
50 | current ido-ubiquitous.el is just a stub that loads ido-cr+ and | |
51 | displays a deprecation warning. | |
52 | ||
53 | 2017-06-01 Ryan C. Thompson <rct@thompsonclan.org> | |
54 | ||
55 | * ido-completing-read+.el (ido-completing-read+): Don't use ido if | |
56 | the collection is empty, since doing so would be pointless. | |
57 | ||
58 | * ido-ubiquitous.el (ido-ubiquitous-default-command-overrides): | |
59 | Update some overrides | |
60 | ||
61 | * ido-describe-fns.el (ido-descfns-maybe-load-prefixes): Add | |
62 | support for the auto-loading feature of describe-variable and | |
63 | similar commands. | |
64 | ||
0 | 65 | 2017-03-13 Ryan C. Thompson <rct@thompsonclan.org> |
1 | 66 | |
2 | 67 | * ido-ubiquitous.el (ido-cr+--explain-fallback): Fix |
0 | # ido-ubiquitous # | |
1 | ||
0 | # ido-completing-read+ (formerly ido-ubiquitous) # | |
1 | ||
2 | [![Build Status](https://travis-ci.org/DarwinAwardWinner/ido-completing-read-plus.svg?branch=master)](https://travis-ci.org/DarwinAwardWinner/ido-completing-read-plus) | |
2 | 3 | [![MELPA Stable](https://stable.melpa.org/packages/ido-ubiquitous-badge.svg)](https://stable.melpa.org/#/ido-ubiquitous) |
3 | 4 | [![Join the chat at https://gitter.im/DarwinAwardWinner/ido-ubiquitous](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/DarwinAwardWinner/ido-ubiquitous?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) |
4 | 5 | |
6 | 7 | completion with ido completion wherever it is possible to do so |
7 | 8 | without breaking things. |
8 | 9 | |
9 | Get it from MELPA: https://stable.melpa.org/#/ido-ubiquitous | |
10 | ||
11 | ## Version 3.0 changes ## | |
12 | ||
13 | Long-time users should know that ido-ubiquitous version 3.0 is a major | |
14 | update, including a split into two packages, and some of the | |
15 | configuration options have changed in non-backwards-compatible ways. | |
16 | If you have customized any options ido-ubiquitous, be sure to check | |
17 | out `M-x customize-group ido-ubiquitous` and `M-x customize-group | |
18 | ido-completing-read+` after updating to 3.0 and make sure the new | |
19 | settings are to your liking. | |
10 | Get it from MELPA: https://stable.melpa.org/#/ido-completing-read+ | |
11 | ||
12 | ## Version 4.0 changes ## | |
13 | ||
14 | Long-time users should know that ido-completing-read+ version 4.0 is a | |
15 | major update. The previously separate ido-ubiquitous package has been | |
16 | merged into ido-completing-read+, which now provides all the features | |
17 | of both packages. The distinction between "new" and "old" default | |
18 | selection styles has been eliminated and replaced by a new variable | |
19 | `ido-cr+-no-default-action` (see [FAQ][1] for details), and the | |
20 | override system has been accordingly simplified into just a blacklist | |
21 | and a whitelist. If you have previously customized any ido-ubiquitous | |
22 | options, be sure to check out | |
23 | ||
24 | `M-x customize-group ido-completing-read+` | |
25 | ||
26 | after updating to 4.0 and make sure the new settings are to your | |
27 | liking. | |
28 | ||
29 | This short-lived ido-describe-fns package has likewise been subsumed | |
30 | into this one. | |
31 | ||
32 | [1]: #why-does-ret-sometimes-not-select-the-first-completion-on-the-list--why-is-there-an-empty-entry-at-the-beginning-of-the-completion-list--what-happened-to-old-style-default-selection | |
20 | 33 | |
21 | 34 | # How to enable ido in as many places as possible # |
22 | 35 | |
33 | 46 | (ido-mode 1) |
34 | 47 | (ido-everywhere 1) |
35 | 48 | |
36 | ## ido-ubiquitous (this package) ## | |
37 | ||
38 | Install this package [from MELPA](http://melpa.org/#/ido-ubiquitous) | |
49 | ## ido-completing-read+ (this package) ## | |
50 | ||
51 | Install this package [from MELPA](http://melpa.org/#/ido-completing-read+) | |
39 | 52 | and then turn on `ido-ubiquitous-mode`: |
40 | 53 | |
41 | (require 'ido-ubiquitous) | |
54 | (require 'ido-completing-read+) | |
42 | 55 | (ido-ubiquitous-mode 1) |
43 | 56 | |
44 | 57 | ## Smex ## |
81 | 94 | (require 'crm-custom) |
82 | 95 | (crm-custom-mode 1) |
83 | 96 | |
84 | Remember that when using this mode, completion for affected commands | |
85 | will continue to read additional items until you use C-j to enter an | |
86 | empty input, which terminates the completion. (Due to this quirk, I do | |
87 | not find this mode to be very useful in conjunction with ido, but it | |
88 | does work.) | |
97 | Make sure to read and understand the FAQ entry below about the empty | |
98 | entry at the beginning of the completion list before using this mode, | |
99 | or using it will likely be very confusing. | |
89 | 100 | |
90 | 101 | ## Packages with built-in ido support ## |
91 | 102 | |
92 | 103 | Lastly, some packages already provide their own interfaces to ido, so |
93 | ido-ubiquitous specifically avoids interfering with these. If you use | |
94 | any of the following packages, you need to enable ido for each of them | |
95 | separately. | |
96 | ||
97 | * Magit: `(setq magit-completing-read-function 'magit-ido-completing-read)` | |
98 | * Gnus: `(setq gnus-completing-read-function 'gnus-ido-completing-read)` | |
104 | ido-completing-read+ specifically avoids interfering with these. If | |
105 | you use any of the following packages, you need to enable ido for each | |
106 | of them separately. | |
107 | ||
108 | * [Magit](https://magit.vc/): `(setq magit-completing-read-function 'magit-ido-completing-read)` | |
109 | * [Gnus](http://www.gnus.org/): `(setq gnus-completing-read-function 'gnus-ido-completing-read)` | |
110 | * [ESS](https://ess.r-project.org/): `(setq ess-use-ido t)` | |
111 | ||
112 | ## icomplete-mode ## | |
113 | ||
114 | For any case where ido cannot be used, there is another older mode | |
115 | called `icomplete-mode` that integrates with standard emacs completion | |
116 | and adds some ido-like behavior. It is built in to emacs, so no | |
117 | installation is necessary. Just load the file and enable the mode: | |
118 | ||
119 | (require 'icomplete) | |
120 | (icomplete-mode 1) | |
99 | 121 | |
100 | 122 | # Frequently asked questions # |
101 | 123 | |
102 | ## How does ido-ubiquitous decide when to replace `completing-read`? <br/> Why don't some commands use ido completion? ## | |
103 | ||
104 | Emacs' `completing-read` is a complex function with many advanced | |
105 | features and some quirks that are only maintained for backwards | |
106 | compatibility. Not all of these features are supported by ido, so it | |
107 | is impossible to always replace `completing-read` with ido completion. | |
108 | Trying to use ido when these features are requested can completely | |
109 | break the completion system. So, by default ido-ubiquitous tries to | |
110 | get out of the way whenever it detects that these features might be | |
111 | used by a given call to `completing-read`. Furthermore, it's not | |
112 | always possible to detect based on the arguments to `completing-read` | |
113 | whether such ido-incompatible features are being used or not. | |
114 | ido-ubiquitous uses a series of heuristics to determine whether | |
115 | unsupported features *might* be used, and also supports an override | |
116 | feature to correct it when the heuristics get things wrong. | |
117 | ||
118 | Each time a function invokes `completing-read`, ido-ubiquitous selects | |
119 | one of 3 modes: | |
120 | ||
121 | * `enable`: use ido completion; | |
122 | * `enable-old`: use ido completion, but with a compatibility fix for | |
123 | old-style default selection; and | |
124 | * `disable`: no ido completion. | |
125 | ||
126 | The following describes in detail how ido-ubiquitous selects the | |
127 | appropriate mode, and what to do when you think it is making the wrong | |
128 | choice. | |
129 | ||
130 | ### Disabling ido completion when the collection is very large ### | |
131 | ||
132 | Ido can get slow on very large collections, so by default | |
133 | ido-ubiquitous disables itself for collections with more than 30,000 | |
134 | items in them. This rule takes precedence over anything else, even | |
135 | overrides that explicitly enable ido completion for a command. | |
136 | ||
137 | You can change the large collection threshold by customizing | |
138 | `ido-cr+-max-items`. | |
139 | ||
140 | ### Disabling ido completion when the collection is a function ### | |
141 | ||
142 | One feature of `completing-read` is that the collection argument can | |
143 | be a function. This function could simply return a list of all | |
144 | possible completions, in which case it would be safe to use ido, or it | |
145 | could implement a completely new completion system, in which case | |
146 | using ido would interfere with this new completion system (for an | |
147 | example of this, see the `tmm` command). But ido-ubiquitous cannot | |
148 | tell by looking at the function which kind it is, so it errs on the | |
149 | side of caution and disables itself whenever the collection is a | |
150 | function, unless an override exists telling it that the command is | |
151 | safe for ido completion. You can turn off this safeguard by | |
152 | customizing `ido-ubiquitous-allow-on-functional-collection`. Be aware | |
153 | that enabling this will likely break completion entirely in any | |
154 | command that uses this feature to implement non-standard completion. | |
155 | ||
156 | If you run across a command that unexpectedly uses normal Emacs | |
157 | completion instead of ido completion, it's likely that either this or | |
158 | the previous option is to blame. | |
159 | ||
160 | ### Disabling or enabling ido completion by overrides ### | |
161 | ||
162 | If ido-ubiquitous is not running for a command where is should be due | |
163 | to the functional collection rule, you can add an override for that | |
164 | command by using `M-x customize-variable | |
165 | ido-ubiquitous-command-overrides`. Conversely, if ido completion | |
166 | causes problems for a command, you can also use this to disable | |
167 | ido-ubiquitous for that command. | |
168 | ||
169 | ## What is old-style default selection? ## | |
170 | ||
171 | The `enable-old` mode of operation is required because the old way for | |
172 | `completing-read` to indicate that the user simply pressed RET and | |
173 | selected the default option was to return an empty string. When this | |
174 | old-style mode is used, `completing-read` doesn't even know what the | |
175 | default is *supposed* to be -- the calling code handles all of that. | |
176 | But in ido, simply pressing RET will return the first item of the | |
177 | list, not an empty string. The way to enter an empty string in ido is | |
178 | C-j. The `enable-old` mode enables ido completion, but swaps the | |
179 | meaning of C-j and RET if you haven't entered any text or cycled the | |
180 | options yet (once you do either of those, C-j and RET regain their | |
181 | standard meanings). This allows you to select the default by pressing | |
182 | RET as soon as the completion prompt appears, as intended (C-j would | |
183 | select the first item). | |
184 | ||
185 | Unfortunately, there is no way for ido-ubiquitous to detect when a | |
186 | command is using this old-style default selection, so instead it uses | |
187 | a built-in set of overrides telling it about commands that are known | |
188 | to use old-style defaults. If you discover a command where pressing | |
189 | RET or C-j at an empty prompt is not doing what you expect it to, | |
190 | there's a good chance that you need to add an `enable-old` override | |
191 | for that command to `ido-ubiquitous-command-overrides`. Luckily, since | |
192 | this is an obsolete usage pattern, it is unlikely that any Elisp | |
193 | functions written since 1990 or so will need to be added to this list. | |
194 | Hopefully all uses of old-style completion will eventually be | |
195 | eliminated, and with them, the need for this feature of | |
196 | ido-ubiquitous. | |
197 | ||
198 | ## How can I troubleshoot when ido-ubiquitous isn't doing what I want? ## | |
199 | ||
200 | First, invoke the `ido-ubiquitous-debug-mode` and `ido-cr+-debug-mode` | |
201 | commands. Then, with these two modes active, run the command(s) that | |
202 | you are having trouble with, and when the completion prompt appears, | |
203 | make a selection to complete the process. Then, examine the Messages | |
204 | buffer, where ido-ubiquitous will explain which mode of operation it | |
205 | selected and why. Based on this, you can add an override to | |
206 | `ido-ubiquitous-command-overrides`. If you are not familiar with the | |
207 | structure of this variable, I recommend using `M-x customize-variable` | |
208 | to edit it, which will help you get it right. If ido completion was | |
209 | skipped ido completion because the collection was too large, try | |
210 | giving `ico-cr+-max-items` a larger value, or set it to nil if your | |
211 | computer is fast enough to handle any size of collection. | |
212 | ||
213 | Updates to ido-ubiquitous often include new overrides, but Emacs will | |
214 | not edit your override variables if you have already customized them. | |
215 | So, if you have recently upgraded ido-ubiquitous, remember to invoke | |
216 | `ido-ubiquitous-restore-default-overrides` to add in any new | |
217 | overrides. (In the future, this process may become automatic: | |
218 | https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/90) | |
219 | ||
220 | ## Where can I report bugs or suggest new overrides? ## | |
221 | ||
222 | If you end up adding any overrides, please also report them at | |
124 | ## How does ido-ubiquitous-mode decide when to replace `completing-read`? <br/> Why don't some commands use ido completion? ## | |
125 | ||
126 | Emacs' `completing-read` is a complex function with many complex | |
127 | features. Not all of these features are supported by ido, so it is | |
128 | impossible to always replace `completing-read` with ido completion. | |
129 | Trying to use ido when these features are requested can cause | |
130 | confusing and unexpected behavior or even completely break the | |
131 | completion system. So, ido-completing-read+ tries to get out of the | |
132 | way whenever it detects that these features might be used by a given | |
133 | call to `completing-read`. Furthermore, it's not always possible to | |
134 | detect based on the arguments to `completing-read` whether such | |
135 | ido-incompatible features are being used or not, so | |
136 | ido-completing-read+ also comes with a blacklist of functions that are | |
137 | known not to work with ido. You can inspect this blacklist using | |
138 | ||
139 | `M-x describe-variable ido-cr+-function-blacklist` | |
140 | ||
141 | If you want to know why a certain command isn't getting ido | |
142 | completion, you can enable `ido-cr+-debug-mode` and then run the | |
143 | command. There should then be a line in the `*Messages*` buffer that | |
144 | explains the reason for disabling ido completion. | |
145 | ||
146 | ## Why does RET sometimes not select the first completion on the list? <br/> Why is there an empty entry at the beginning of the completion list? <br/> What happened to old-style default selection? ## | |
147 | ||
148 | The simplest way to think about this is that if the command that | |
149 | called `completing-read` didn't specify a default, then the default is | |
150 | the empty string. In other words, `""` is the default default. | |
151 | ||
152 | Previous versions of ido-ubiquitous-mode gave special consideration to | |
153 | cases where a default value was not provided to `completing-read` and | |
154 | the user pressed RET without entering any text. The expected behavior | |
155 | is that `completing-read` should return the empty string in this case, | |
156 | which indicates to the calling function that the user did not select | |
157 | any completion. This conflicts with the standard ido behavior of | |
158 | selecting the first available completion when pressing RET, and this | |
159 | conflict was previously resolved by having two different modes that | |
160 | differed in their handling of RET on an empty input. Now there is only | |
161 | one mode, and the no-default case is handled by acting as if the empty | |
162 | string was specified as the default, which more closely matches the | |
163 | behavior of standard emacs completion. Since you, the user, have no | |
164 | way of knowing how `completing-read' was called, you can tell when | |
165 | this is occurring by watching for the appearance of an empty | |
166 | completion at the front of the list. Compare: | |
167 | ||
168 | If the command specifies apple as the default when calling | |
169 | `completing-read`, the prompt will look like this, and pressing RET | |
170 | will select "apple": | |
171 | ||
172 | Pick a fruit: {apple | banana | cherry | date} | |
173 | ||
174 | However, if the command does not specify any default, an extra empty | |
175 | option is displayed before the first option, and pressing RET will | |
176 | select this empty option and return "": | |
177 | ||
178 | Pick a fruit: { | apple | banana | cherry | date} | |
179 | ||
180 | To select "apple" instead, you must first press the right arrow key | |
181 | once, or type an "a", before pressing RET. | |
182 | ||
183 | However, some commands don't take this quirk of `completing-read` into | |
184 | account and don't expect it to ever return an empty string when | |
185 | `require-match` is non-nil. You can accommodate these functions by | |
186 | adding them to `ido-cr+-nil-def-alternate-behavior-list`. | |
187 | ||
188 | ## How can I troubleshoot when ido-completing-read+ isn't doing what I want? ## | |
189 | ||
190 | First, invoke the `ido-cr+-debug-mode` command. Then, run the command | |
191 | or code that you are having trouble with, and when the completion | |
192 | prompt appears, make a selection to complete the process. Then, | |
193 | examine the Messages buffer, where ido-completing-read+ will explain | |
194 | which mode of operation it selected and why. Based on this, you can | |
195 | add an entry to `ido-cr+-function-blacklist`, or take some other | |
196 | appropriate action. | |
197 | ||
198 | Updates to ido-completing-read+ may include new blacklist entries, but | |
199 | Emacs will not edit your override variables if you have already | |
200 | customized them. So, if you have recently upgraded | |
201 | ido-completing-read+, remember to invoke `ido-cr+-update-blacklist` to | |
202 | add in any new overrides. By default, ido-completing-read+ will remind | |
203 | you to do this whenever a new version adds to the blacklist. For more | |
204 | information, see: | |
205 | ||
206 | M-x describe-variable ido-cr+-auto-update-blacklist | |
207 | ||
208 | ## Where can I report bugs? ## | |
209 | ||
210 | If you end up adding any blacklist entries, please report them at | |
223 | 211 | https://github.com/DarwinAwardWinner/ido-ubiquitous/issues so I can |
224 | 212 | incorporate them into the defaults for future versions. You can also |
225 | report any bugs you find in ido-ubiquitous. | |
226 | ||
227 | ## I'm getting some weird warnings from ido-ubiquitous when Emacs starts. ## | |
213 | report any bugs you find in ido-completing-read+. | |
214 | ||
215 | ## I'm getting some weird warnings from ido-completing-read+ when Emacs starts. ## | |
228 | 216 | |
229 | 217 | I've gotten numerous reports about nonsensical warnings produced by |
230 | ido-ubiquitous, such as "free variable" warnings about variables that | |
218 | this package, such as "free variable" warnings about variables that | |
231 | 219 | are most definitely properly declared, or warnings that only appear |
232 | when ido-ubiquitous is loaded after another unrelated package. For | |
233 | many of these warnings, I've never been able to discover the cause or | |
234 | reproduce the warnings myself, and I've given up trying to figure it | |
235 | out. Please don't report any new bugs about variable warnings *unless* | |
236 | you can tell me how to consistently reproduce them starting from | |
237 | `emacs -Q`. If you are an Emacs expert who knows how to fix these | |
238 | warnings, please let me know. | |
220 | when ido-completing-read+ is loaded after another unrelated package. | |
221 | For many of these warnings, I've never been able to discover the cause | |
222 | or consistently reproduce the warnings myself, and I've given up | |
223 | trying to figure it out. Please don't report any new bugs about | |
224 | variable warnings *unless* you can tell me how to consistently | |
225 | reproduce them starting from `emacs -Q`. If you are an Emacs expert | |
226 | who knows how to fix these warnings, please let me know. | |
239 | 227 | |
240 | 228 | You can see the bug reports about weird warnings |
241 | 229 | [here](https://github.com/DarwinAwardWinner/ido-ubiquitous/issues?utf8=%E2%9C%93&q=label%3Abizarre-unexplainable-scoping-issues+). |
244 | 232 | |
245 | 233 | All users should just use the master branch, or better yet, install |
246 | 234 | from MELPA. The bleeding-edge branch is where I test experimental and |
247 | unfinished features. Because ido-ubiquitous hooks deeply into the | |
248 | bowels of Emacs, a bug in ido-ubiquitous could easily freeze or crash | |
249 | Emacs entirely. Additionally, some bug only show up when | |
250 | ido-ubiquitous is installed and compiled as a package. So I test every | |
251 | new feature myself for some time on this branch before pushing to the | |
252 | master branch. If you report a bug, I might develop a fix for it on | |
253 | the bleeding edge branch and ask then you to try this branch. | |
235 | unfinished features. Because ido-completing-read+ hooks deeply into | |
236 | the bowels of Emacs, a bug in ido-completing-read+ could easily freeze | |
237 | or crash Emacs entirely. Additionally, some bug only show up when | |
238 | ido-completing-read+ is installed and compiled as a package. So I test | |
239 | every new feature myself for some time on this branch before pushing | |
240 | to the master branch. If you report a bug, I might develop a fix for | |
241 | it on the bleeding edge branch and ask then you to try this branch. | |
254 | 242 | Otherwise, normal users don't need to think about this branch. |
255 | 243 | |
256 | # ido-completing-read+ # | |
257 | ||
258 | As of version 3.0, most of the core functionality of ido-ubiquitous | |
259 | has been spun off into a separate library called ido-completing-read+, | |
260 | or "ido-cr+" for short. ido-cr+ incorporates all the features of | |
261 | ido-ubiquitous that are actually just generic improvements to ido that | |
262 | should probably always be enabled. It implements these fixes in a | |
263 | single function `ido-completing-read+`, which should be suitable as a | |
264 | drop-in replacement for either `ido-completing-read` or | |
265 | `completing-read`. Notably, unlike the original `ido-completing-read`, | |
266 | `ido-completing-read+` should always do something useful, by falling | |
267 | back to normal completion when ido completion won't work. | |
268 | Additionally, it allows you to manually fall back using C-f and C-b, | |
269 | in the same way you can use those keys to switch between file and | |
270 | buffer completion in ido. As a user, you don't really need to know | |
271 | anything about ido-cr+. However, if you are writing an Emacs package | |
272 | and would like to incorporate ido completion, you may wish to use | |
273 | ido-cr+ to get more robust completion with fewer weird edge cases. | |
244 | ## Running the tests | |
245 | ||
246 | This package comes with a test suite. If you want to run it yourself, | |
247 | first install the [cask](http://cask.readthedocs.io/en/latest/) | |
248 | dependency manager. Then, from the package directory, run `cask | |
249 | install` to install all the development dependencies, in | |
250 | particular | |
251 | [buttercup](https://github.com/jorgenschaefer/emacs-buttercup). | |
252 | Finally, to run the tests, execute `cask exec buttercup -L .`. Please | |
253 | run this test suite before submitting any pull requests, and note in | |
254 | the pull request whether any of the tests fail. |
0 | 0 | ;;; ido-completing-read+.el --- A completing-read-function using ido -*- lexical-binding: t -*- |
1 | 1 | |
2 | ;; Copyright (C) 2015 Ryan C. Thompson | |
2 | ;; Copyright (C) 2011-2017 Ryan C. Thompson | |
3 | 3 | |
4 | 4 | ;; Filename: ido-completing-read+.el |
5 | 5 | ;; Author: Ryan Thompson |
6 | 6 | ;; Created: Sat Apr 4 13:41:20 2015 (-0700) |
7 | ;; Version: 3.16 | |
8 | ;; Package-Requires: ((emacs "24.1") (cl-lib "0.5")) | |
9 | ;; URL: https://github.com/DarwinAwardWinner/ido-ubiquitous | |
7 | ;; Version: 4.5 | |
8 | ;; Package-Requires: ((emacs "24.4") (cl-lib "0.5") (s "0.1") (memoize "1.1")) | |
9 | ;; URL: https://github.com/DarwinAwardWinner/ido-completing-read-plus | |
10 | 10 | ;; Keywords: ido, completion, convenience |
11 | 11 | |
12 | 12 | ;; This file is NOT part of GNU Emacs. |
14 | 14 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
15 | 15 | ;; |
16 | 16 | ;;; Commentary: |
17 | ||
18 | ;; If you use the excellent `ido-mode' for efficient completion of | |
19 | ;; file names and buffers, you might wonder if you can get ido-style | |
20 | ;; completion everywhere else too. Well, that's what this package | |
21 | ;; does! ido-ubiquitous is here to enable ido-style completion for | |
22 | ;; (almost) every function that uses the standard completion function | |
23 | ;; `completing-read'. | |
17 | 24 | |
18 | 25 | ;; This package implements the `ido-completing-read+' function, which |
19 | 26 | ;; is a wrapper for `ido-completing-read'. Importantly, it detects |
20 | 27 | ;; edge cases that ordinary ido cannot handle and either adjusts them |
21 | 28 | ;; so ido *can* handle them, or else simply falls back to Emacs' |
22 | ;; standard completion instead. | |
29 | ;; standard completion instead. Hence, you can safely set | |
30 | ;; `completing-read-function' to `ido-completing-read+' without | |
31 | ;; worrying about breaking completion features that are incompatible | |
32 | ;; with ido. | |
33 | ||
34 | ;; To use this package, call `ido-ubiquitous-mode' to enable the mode, | |
35 | ;; or use `M-x customize-variable ido-ubiquitous-mode' it to enable it | |
36 | ;; permanently. Once the mode is enabled, most functions that use | |
37 | ;; `completing-read' will now have ido completion. If you decide in | |
38 | ;; the middle of a command that you would rather not use ido, just use | |
39 | ;; C-f or C-b at the end/beginning of the input to fall back to | |
40 | ;; non-ido completion (this is the same shortcut as when using ido for | |
41 | ;; buffers or files). | |
42 | ||
43 | ;; Note that `completing-read-default' is a very general function with | |
44 | ;; many complex behaviors that ido cannot emulate. This package | |
45 | ;; attempts to detect some of these cases and avoid using ido when it | |
46 | ;; sees them. So some functions will not have ido completion even when | |
47 | ;; this mode is enabled. Some other functions have ido disabled in | |
48 | ;; them because their packages already provide support for ido via | |
49 | ;; other means (for example, magit). See `M-x describe-variable | |
50 | ;; ido-cr+-function-blacklist' for more information. | |
51 | ||
52 | ;; ido-completing-read+ version 4.0 is a major update. The formerly | |
53 | ;; separate package ido-ubiquitous has been subsumed into | |
54 | ;; ido-completing-read+, so ido-ubiquitous 4.0 is just a wrapper that | |
55 | ;; loads ido-completing-read+ and displays a warning about being | |
56 | ;; obsolete. If you have previously customized ido-ubiquitous, be sure | |
57 | ;; to check out `M-x customize-group ido-completing-read-plus' after | |
58 | ;; updating to 4.0 and make sure the new settings are to your liking. | |
23 | 59 | |
24 | 60 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
25 | 61 | ;; |
40 | 76 | ;; |
41 | 77 | ;;; Code: |
42 | 78 | |
43 | (defconst ido-completing-read+-version "3.16" | |
44 | "Currently running version of ido-ubiquitous. | |
79 | (defconst ido-completing-read+-version "4.5" | |
80 | "Currently running version of ido-completing-read+. | |
45 | 81 | |
46 | 82 | Note that when you update ido-completing-read+, this variable may |
47 | 83 | not be updated until you restart Emacs.") |
48 | 84 | |
49 | 85 | (require 'ido) |
50 | 86 | (require 'cl-lib) |
87 | (require 'cus-edit) | |
88 | (require 's) | |
89 | (require 'memoize) | |
51 | 90 | |
52 | 91 | ;;; Debug messages |
53 | 92 | |
59 | 98 | :global t |
60 | 99 | :group 'ido-completing-read-plus) |
61 | 100 | |
62 | (defun ido-cr+--debug-message (format-string &rest args) | |
101 | (defsubst ido-cr+--debug-message (format-string &rest args) | |
63 | 102 | (when ido-cr+-debug-mode |
64 | 103 | (apply #'message (concat "ido-completing-read+: " format-string) args))) |
65 | 104 | |
66 | ;;; Core code | |
105 | ;;; Ido variables | |
106 | ||
107 | ;; For unknown reasons, these variables need to be re-declared here to | |
108 | ;; silence byte-compiler warnings, despite already being declared in | |
109 | ;; ido.el. | |
110 | ||
111 | (defmacro define-ido-internal-var (symbol &optional initvalue docstring) | |
112 | "Declare and initialize an ido internal variable. | |
113 | ||
114 | This is used to suppress byte-compilation warnings about | |
115 | reference to free variables when ido-cr+ attempts to access | |
116 | internal ido variables with no initial value set. Such variables | |
117 | are originally declared like `(defvar VARNAME)'. | |
118 | ||
119 | This is a wrapper for `defvar' that supplies a default for the | |
120 | INITVALUE and DOCSTRING arguments." | |
121 | `(defvar ,symbol ,initvalue | |
122 | ,(or docstring | |
123 | "Internal ido variable. | |
124 | ||
125 | This variable was originally declared in `ido.el' without an | |
126 | initial value or docstring. The documentation you're reading | |
127 | comes from re-declaring it in `ido-completing-read+.el' in order | |
128 | to suppress some byte-compilation warnings. Setting another | |
129 | package's variable is not safe in general, but in this case it | |
130 | should be, because ido always let-binds this variable before | |
131 | using it, so the initial value shouldn't matter."))) | |
132 | ||
133 | (define-ido-internal-var ido-context-switch-command) | |
134 | (define-ido-internal-var ido-cur-list) | |
135 | (define-ido-internal-var ido-cur-item) | |
136 | (define-ido-internal-var ido-require-match) | |
137 | (define-ido-internal-var ido-process-ignore-lists) | |
67 | 138 | |
68 | 139 | ;;;###autoload |
69 | (defvar ido-cr+-enable-next-call nil | |
70 | "If non-nil, then the next call to `ido-completing-read' is by `ido-completing-read+'.") | |
71 | ;;;###autoload | |
72 | (defvar ido-cr+-enable-this-call nil | |
73 | "If non-nil, then the current call to `ido-completing-read' is by `ido-completing-read+'") | |
140 | (defvar ido-cr+-minibuffer-depth -1 | |
141 | "Minibuffer depth of the most recent ido-cr+ activation. | |
142 | ||
143 | If this equals the current minibuffer depth, then the minibuffer | |
144 | is currently being used by ido-cr+, and ido-cr+ feature will be | |
145 | active. Otherwise, something else is using the minibuffer and | |
146 | ido-cr+ features will be deactivated to avoid interfering with | |
147 | the other command. | |
148 | ||
149 | This is set to -1 by default, since `(minibuffer-depth)' should | |
150 | never return this value.") | |
151 | ||
152 | (defvar ido-cr+-assume-static-collection nil | |
153 | "If non-nil, ido-cr+ will assume that the collection is static. | |
154 | ||
155 | This is used to avoid unnecessary work in the case where the | |
156 | collection is a function, since a function collection could | |
157 | potentially change the set of completion candidates | |
158 | dynamically.") | |
159 | ||
160 | (defvar ido-cr+-current-command nil | |
161 | "Command most recently invoked by `call-interactively'. | |
162 | ||
163 | This is necessary because `command-execute' and | |
164 | `call-interactively' do not set `this-command'. Instead, the C | |
165 | code that calls `command-execute' sets it beforehand, so using | |
166 | either of those functions directly won't set `this-command'.") | |
167 | ||
168 | (defvar ido-cr+-dynamic-collection nil | |
169 | "Stores the collection argument if it is a function. | |
170 | ||
171 | This allows ido-cr+ to update the set of completion candidates | |
172 | dynamically.") | |
173 | ||
174 | (defvar ido-cr+-previous-dynamic-update-texts nil | |
175 | "Values of `ido-text' for the last few dynamic collection updates. | |
176 | ||
177 | This is used in `ido-cr+-update-dynamic-collection' as an LRU | |
178 | cache of recent values of `ido-text' in order to skip re-checking | |
179 | prefixes of these strings.") | |
180 | ||
181 | (defvar ido-cr+-dynamic-update-idle-time 0.25 | |
182 | "Time to wait before updating dynamic completion list.") | |
183 | ||
184 | (defvar ido-cr+-dynamic-update-timer nil | |
185 | "Idle timer for updating dynamic completion list.") | |
186 | ||
187 | (defvar ido-cr+-exhibit-pending nil | |
188 | "This is non-nil after calling `ido-tidy' until the next call to `ido-exhibit'. | |
189 | ||
190 | Typically this is non-nil while any command is running and nil at all | |
191 | other times, since those two functions are in `pre-command-hook' | |
192 | and `post-command-hook' respectively. In particular, this will | |
193 | generally be nil while running an idle timer.") | |
194 | ||
195 | (make-obsolete-variable | |
196 | 'ido-cr+-no-default-action | |
197 | " This variable no longer has any effect. Customize `ido-cr+-nil-def-alternate-behavior-list' instead." | |
198 | "4.2") | |
199 | ||
200 | (defvar ido-cr+-orig-completing-read-args nil | |
201 | "Original arguments passed to `ido-completing-read+'. | |
202 | ||
203 | These are used for falling back to `completing-read-default'.") | |
204 | ||
205 | (defvar ido-cr+-all-completions-memoized nil | |
206 | "Memoized version of `all-completions'. | |
207 | ||
208 | During completion with dynamic collection, this variable is set | |
209 | to a memoized copy of `all-completions'.") | |
210 | ||
211 | (defvar ido-cr+-all-prefix-completions-memoized nil | |
212 | "Memoized version of `ido-cr+-all-prefix-completions'. | |
213 | ||
214 | During completion with dynamic collection, this variable is set | |
215 | to a memoized copy of `ido-cr+-all-prefix-completions'.") | |
216 | ||
217 | (defvar ido-cr+-active-restrictions nil | |
218 | "List of restrictions in place from `ido-restrict-to-matches'. | |
219 | ||
220 | Each element is a cons cell of (REMOVEP . TEXT), where REMOVEP is | |
221 | the prefix argument to `ido-restrict-to-matches' and TEXT is the | |
222 | pattern used to restrict.") | |
74 | 223 | |
75 | 224 | (defgroup ido-completing-read-plus nil |
76 | 225 | "Extra features and compatibility for `ido-completing-read'." |
120 | 269 | widget))))) |
121 | 270 | :group 'ido-completing-read-plus) |
122 | 271 | |
272 | (defcustom ido-cr+-function-blacklist | |
273 | '(read-file-name-internal | |
274 | read-buffer | |
275 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/60 | |
276 | todo-add-category | |
277 | ;; Gnus already supports ido on its own | |
278 | gnus-emacs-completing-read | |
279 | gnus-iswitchb-completing-read | |
280 | grep-read-files | |
281 | ;; Magit already supports ido on its own | |
282 | magit-builtin-completing-read | |
283 | ;; ESS already supports ido on its own | |
284 | ess-completing-read | |
285 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/39 | |
286 | Info-read-node-name | |
287 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/44 | |
288 | tmm-prompt) | |
289 | "Functions & commands for which ido-cr+ should be disabled. | |
290 | ||
291 | Each entry can be either a symbol or a string. A symbol means to | |
292 | fall back specifically for the named function. A regular | |
293 | expression means to fall back for any function whose name matches | |
294 | that regular expression. When ido-cr+ is called through | |
295 | `completing-read', if any function in the call stack of the | |
296 | current command matches any of the blacklist entries, ido-cr+ | |
297 | will be disabled for that command. Additionally, if the | |
298 | collection in the call to `completing-read' matches any of the | |
299 | blacklist entries, ido-cr+ will be disabled. | |
300 | ||
301 | Note that using specific function names is generally preferable | |
302 | to regular expressions, because the associated function | |
303 | definitions will be compared directly, so if the same function is | |
304 | called by another name, it should still trigger the fallback. For | |
305 | regular expressions, only name-based matching is possible." | |
306 | :group 'ido-completing-read-plus | |
307 | :type '(repeat (choice (symbol :tag "Function or command name") | |
308 | (string :tag "Regexp")))) | |
309 | ||
310 | (defcustom ido-cr+-function-whitelist | |
311 | nil | |
312 | "Functions & commands for which ido-cr+ should be enabled. | |
313 | ||
314 | If this variable is nil, the whitelist will not be used, and | |
315 | ido-cr+ will be allowed in all functions/commands not listed in | |
316 | `ido-cr+-function-backlist'. | |
317 | ||
318 | If this variable is non-nil, ido-cr+'s whitelisting mode will be | |
319 | enabled, and ido-cr+ will be disabled for *all* functions unless | |
320 | they match one of the entries. Matching is done in the same | |
321 | manner as `ido-cr+-function-blacklist', and blacklisting takes | |
322 | precedence over whitelisting." | |
323 | :group 'ido-completing-read-plus | |
324 | :type '(repeat (choice (symbol :tag "Function or command name") | |
325 | (string :tag "Regexp")))) | |
326 | ||
327 | (defcustom ido-cr+-nil-def-alternate-behavior-list | |
328 | '("\\`describe-\\(function\\|variable\\)\\'" | |
329 | "\\`wl-" | |
330 | ;; https://github.com/mrkkrp/ebal/issues/12 | |
331 | "\\`ebal-" | |
332 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/4 | |
333 | webjump | |
334 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/83 | |
335 | where-is | |
336 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/51 | |
337 | find-tag | |
338 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/89 | |
339 | "\\`etags-select-" | |
340 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/58 | |
341 | imenu--completion-buffer | |
342 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/116 | |
343 | project--completing-read-strict | |
344 | ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues/127#issuecomment-319463217 | |
345 | bookmark-completing-read | |
346 | ) | |
347 | "Functions & commands with alternate behavior when DEF is nil. | |
348 | ||
349 | This variable has the same format as | |
350 | `ido-cr+-function-blacklist'. When `ido-completing-read+` is | |
351 | called through `completing-read' by/with any command, function, | |
352 | or collection matched by entries in this list, it will behave | |
353 | differently when DEF is nil. Instead of using the empty string as | |
354 | the default value, it will use the first element of COLLECTION. | |
355 | ||
356 | This is needed for optimal compatibility with commands written | |
357 | under the assumption that REQUIRE-MATCH means that a match is | |
358 | required." | |
359 | :group 'ido-completing-read-plus | |
360 | :type '(repeat (choice (symbol :tag "Function or command name") | |
361 | (string :tag "Regexp")))) | |
362 | ||
363 | (defvaralias 'ido-cr+-nil-def-wall-of-shame 'ido-cr+-nil-def-alternate-behavior-list | |
364 | "Functions and commands whose authors need to read the docstring for `completing-read'. | |
365 | ||
366 | Many functions that call `completing-read' are written with the | |
367 | assumption that the setting the REQUIRE-MATCH argument of | |
368 | `completing-read' to t means it is required to return a match. | |
369 | While that would make logical sense, it's wrong. the docstring | |
370 | for `completing-read' describes the correct behavior. | |
371 | ||
372 | > If the input is null, ‘completing-read’ returns DEF, or the | |
373 | > first element of the list of default values, or an empty string | |
374 | > if DEF is nil, regardless of the value of REQUIRE-MATCH. | |
375 | ||
376 | This can be avoided by passing an element of COLLECTION as DEF | |
377 | instead of leaving it as nil.") | |
378 | ||
123 | 379 | ;;;###autoload |
124 | 380 | (defcustom ido-cr+-replace-completely nil |
125 | 381 | "If non-nil, replace `ido-completeing-read' completely with ido-cr+. |
127 | 383 | Enabling this may interfere with or cause errors in other |
128 | 384 | packages that use `ido-completing-read'. If you discover any such |
129 | 385 | incompatibilities, please file a bug report at |
130 | https://github.com/DarwinAwardWinner/ido-ubiquitous/issues" | |
386 | https://github.com/DarwinAwardWinner/ido-completing-read-plus/issues" | |
131 | 387 | :type 'boolean) |
132 | 388 | |
133 | 389 | ;; Signal used to trigger fallback |
134 | (put 'ido-cr+-fallback 'error-conditions '(ido-cr+-fallback error)) | |
135 | (put 'ido-cr+-fallback 'error-message "ido-cr+-fallback") | |
136 | ||
137 | (defun ido-cr+--explain-fallback (arg) | |
390 | (define-error 'ido-cr+-fallback "ido-cr+-fallback") | |
391 | ||
392 | (defsubst ido-cr+--explain-fallback (arg) | |
138 | 393 | ;; This function accepts a string, or an ido-cr+-fallback |
139 | 394 | ;; signal. |
140 | 395 | (when ido-cr+-debug-mode |
145 | 400 | ido-cr+-fallback-function arg))) |
146 | 401 | |
147 | 402 | ;;;###autoload |
403 | (defsubst ido-cr+-active () | |
404 | "Returns non-nil if ido-cr+ is currently using the minibuffer." | |
405 | (>= ido-cr+-minibuffer-depth (minibuffer-depth))) | |
406 | ||
407 | (defsubst ido-cr+-default-was-provided () | |
408 | "Returns non-nil if ido-cr+ was passed a non-nil default argument." | |
409 | (and (nth 6 ido-cr+-orig-completing-read-args))) | |
410 | ||
411 | (defun ido-cr+--called-from-completing-read () | |
412 | "Returns non-nil if the most recent call to ido-cr+ was from `completing-read'." | |
413 | (equal (cadr (backtrace-frame 1 'ido-completing-read+)) | |
414 | 'completing-read)) | |
415 | ||
416 | (defmacro ido-cr+-function-is-in-list (fun fun-list &optional list-name) | |
417 | "Return non-nil if FUN matches an entry in FUN-LIST. | |
418 | ||
419 | This is used to check for matches to `ido-cr+-function-blacklist' | |
420 | and `ido-cr+-function-whitelist'. Read those docstrings to see | |
421 | how the matching is done. | |
422 | ||
423 | This is declared as macro only in order to extract the variable | |
424 | name used for the second argument so it can be used in a debug | |
425 | message. It should be called as if it were a normal function." | |
426 | (when (null list-name) | |
427 | (if (symbolp fun-list) | |
428 | (setq list-name (symbol-name fun-list)) | |
429 | (setq list-name "list"))) | |
430 | `(cl-loop | |
431 | for entry in ,fun-list | |
432 | if (cond | |
433 | ;; Nil: Never matches anything | |
434 | ((null entry) | |
435 | nil) | |
436 | ;; Symbol: Compare names and function definitions | |
437 | ((symbolp entry) | |
438 | (or (eq entry ,fun) | |
439 | (let ((entry-def (ignore-errors (indirect-function entry))) | |
440 | (fun-def (ignore-errors (indirect-function ,fun)))) | |
441 | (and | |
442 | fun-def entry-def | |
443 | (eq | |
444 | (indirect-function entry-def) | |
445 | (indirect-function fun-def)))))) | |
446 | ;; String: Do regexp matching against function name if it is a | |
447 | ;; symbol | |
448 | ((stringp entry) | |
449 | (and (symbolp ,fun) | |
450 | (string-match-p entry (symbol-name ,fun)))) | |
451 | ;; Anything else: invalid blacklist entry | |
452 | (t | |
453 | (ido-cr+--debug-message "Ignoring invalid entry in %s: `%S'" ,list-name entry) | |
454 | nil)) | |
455 | return entry | |
456 | ;; If no blacklist entry matches, return nil | |
457 | finally return nil)) | |
458 | ||
459 | (defun ido-cr+-function-is-blacklisted (fun) | |
460 | "Return non-nil if FUN is blacklisted. | |
461 | ||
462 | See `ido-cr+-function-blacklist'." | |
463 | (ido-cr+-function-is-in-list fun ido-cr+-function-blacklist)) | |
464 | ||
465 | (defun ido-cr+-function-is-whitelisted (fun) | |
466 | "Return non-nil if FUN is whitelisted. | |
467 | ||
468 | See `ido-cr+-function-whitelist'." | |
469 | (or (null ido-cr+-function-whitelist) | |
470 | (ido-cr+-function-is-in-list fun ido-cr+-function-whitelist))) | |
471 | ||
472 | ;;;###autoload | |
148 | 473 | (defun ido-completing-read+ (prompt collection &optional predicate |
149 | 474 | require-match initial-input |
150 | 475 | hist def inherit-input-method) |
156 | 481 | be used as the value of `completing-read-function'. Importantly, |
157 | 482 | it detects edge cases that ido cannot handle and uses normal |
158 | 483 | completion for them." |
159 | (let (;; Save the original arguments in case we need to do the | |
160 | ;; fallback | |
161 | (orig-args | |
162 | (list prompt collection predicate require-match | |
163 | initial-input hist def inherit-input-method))) | |
484 | (let* (;; Save the original arguments in case we need to do the | |
485 | ;; fallback | |
486 | (ido-cr+-orig-completing-read-args | |
487 | (list prompt collection predicate require-match | |
488 | initial-input hist def inherit-input-method)) | |
489 | ;; Need to save this since activating the minibuffer once will | |
490 | ;; clear out any temporary minibuffer hooks, which need to get | |
491 | ;; restored before falling back. | |
492 | (orig-minibuffer-setup-hook minibuffer-setup-hook) | |
493 | ;; Need just the string part of INITIAL-INPUT | |
494 | (initial-input-string | |
495 | (cond | |
496 | ((consp initial-input) | |
497 | (car initial-input)) | |
498 | ((stringp initial-input) | |
499 | initial-input) | |
500 | ((null initial-input) | |
501 | "") | |
502 | (t | |
503 | (signal 'wrong-type-argument (list 'stringp initial-input))))) | |
504 | (ido-cr+-active-restrictions nil) | |
505 | ;; If collection is a function, save it for later, unless | |
506 | ;; instructed not to | |
507 | (ido-cr+-dynamic-collection | |
508 | (when (and (not ido-cr+-assume-static-collection) | |
509 | (functionp collection)) | |
510 | collection)) | |
511 | ;; Only memoize if the collection is dynamic. | |
512 | (ido-cr+-all-prefix-completions-memoized | |
513 | (if ido-cr+-dynamic-collection | |
514 | (memoize (indirect-function 'ido-cr+-all-prefix-completions)) | |
515 | 'ido-cr+-all-prefix-completions)) | |
516 | (ido-cr+-all-completions-memoized | |
517 | (if ido-cr+-dynamic-collection | |
518 | (memoize (indirect-function 'all-completions)) | |
519 | 'all-completions)) | |
520 | ;; If the whitelist is empty, everything is whitelisted | |
521 | (whitelisted (not ido-cr+-function-whitelist)) | |
522 | ;; If non-nil, we need alternate nil DEF handling | |
523 | (alt-nil-def nil)) | |
164 | 524 | (condition-case sig |
165 | 525 | (progn |
166 | (cond | |
167 | (inherit-input-method | |
526 | ;; Check a bunch of fallback conditions | |
527 | (when inherit-input-method | |
168 | 528 | (signal 'ido-cr+-fallback |
169 | 529 | '("ido cannot handle non-nil INHERIT-INPUT-METHOD"))) |
170 | ((bound-and-true-p completion-extra-properties) | |
530 | (when (bound-and-true-p completion-extra-properties) | |
171 | 531 | (signal 'ido-cr+-fallback |
172 | 532 | '("ido cannot handle non-nil `completion-extra-properties'"))) |
173 | ((functionp collection) | |
174 | (signal 'ido-cr+-fallback | |
175 | '("ido cannot handle COLLECTION being a function")))) | |
176 | ;; Expand all possible completions | |
177 | (setq collection (all-completions "" collection predicate)) | |
533 | ||
534 | ;; Check for black/white-listed collection function | |
535 | (when (functionp collection) | |
536 | ;; Blacklist | |
537 | (when (ido-cr+-function-is-blacklisted collection) | |
538 | (if (symbolp collection) | |
539 | (signal 'ido-cr+-fallback | |
540 | (list (format "collection function `%S' is blacklisted" collection))) | |
541 | (signal 'ido-cr+-fallback | |
542 | (list "collection function is blacklisted")))) | |
543 | ;; Whitelist | |
544 | (when (and (not whitelisted) | |
545 | (ido-cr+-function-is-whitelisted collection)) | |
546 | (ido-cr+--debug-message | |
547 | (if (symbolp collection) | |
548 | (format "Collection function `%S' is whitelisted" collection) | |
549 | "Collection function is whitelisted")) | |
550 | (setq whitelisted t)) | |
551 | ;; nil DEF list | |
552 | (when (and | |
553 | require-match (null def) | |
554 | (ido-cr+-function-is-in-list | |
555 | collection | |
556 | ido-cr+-nil-def-alternate-behavior-list)) | |
557 | (ido-cr+--debug-message | |
558 | (if (symbolp collection) | |
559 | (format "Using alternate nil DEF handling for collection function `%S'" collection) | |
560 | "Using alternate nil DEF handling for collection function")) | |
561 | (setq alt-nil-def t))) | |
562 | ||
563 | ;; Expand all currently-known completions. | |
564 | (setq collection | |
565 | (if ido-cr+-dynamic-collection | |
566 | (funcall ido-cr+-all-prefix-completions-memoized | |
567 | initial-input-string collection predicate) | |
568 | (all-completions "" collection predicate))) | |
569 | ;; No point in using ido unless there's a collection | |
570 | (when (and (= (length collection) 0) | |
571 | (not ido-cr+-dynamic-collection)) | |
572 | (signal 'ido-cr+-fallback '("ido is not needed for an empty collection"))) | |
178 | 573 | ;; Check for excessively large collection |
179 | 574 | (when (and ido-cr+-max-items |
180 | 575 | (> (length collection) ido-cr+-max-items)) |
183 | 578 | (format |
184 | 579 | "there are more than %i items in COLLECTION (see `ido-cr+-max-items')" |
185 | 580 | ido-cr+-max-items)))) |
186 | ;; ido doesn't natively handle DEF being a list. If DEF is a | |
187 | ;; list, prepend it to COLLECTION and set DEF to just the | |
188 | ;; car of the default list. | |
189 | (when (and def (listp def)) | |
190 | (setq collection | |
191 | (append def | |
192 | (nreverse (cl-set-difference collection def))) | |
193 | def (car def))) | |
194 | ;; Work around a bug in ido when both INITIAL-INPUT and | |
195 | ;; DEF are provided. | |
196 | (let ((initial | |
197 | (or (if (consp initial-input) | |
198 | (car initial-input) | |
199 | initial-input) | |
200 | ""))) | |
201 | (when (and def initial | |
202 | (stringp initial) | |
203 | (not (string= initial ""))) | |
204 | ;; Both default and initial input were provided. So keep | |
205 | ;; the initial input and preprocess the collection list | |
206 | ;; to put the default at the head, then proceed with | |
207 | ;; default = nil. | |
208 | (setq collection (cons def (remove def collection)) | |
209 | def nil))) | |
210 | ;; Ready to do actual ido completion | |
581 | ||
582 | ;; If called from `completing-read', check for | |
583 | ;; black/white-listed commands/callers | |
584 | (when (ido-cr+--called-from-completing-read) | |
585 | ;; Check calling command and `ido-cr+-current-command' | |
586 | (cl-loop | |
587 | for cmd in (list this-command ido-cr+-current-command) | |
588 | ||
589 | if (ido-cr+-function-is-blacklisted cmd) | |
590 | do (signal 'ido-cr+-fallback | |
591 | (list "calling command `%S' is blacklisted" cmd)) | |
592 | ||
593 | if (and (not whitelisted) | |
594 | (ido-cr+-function-is-whitelisted cmd)) | |
595 | do (progn | |
596 | (ido-cr+--debug-message "Command `%S' is whitelisted" cmd) | |
597 | (setq whitelisted t)) | |
598 | ||
599 | if (and | |
600 | require-match (null def) (not alt-nil-def) | |
601 | (ido-cr+-function-is-in-list | |
602 | cmd ido-cr+-nil-def-alternate-behavior-list)) | |
603 | do (progn | |
604 | (ido-cr+--debug-message | |
605 | "Using alternate nil DEF handling for command `%S'" cmd) | |
606 | (setq alt-nil-def t))) | |
607 | ||
608 | ;; Check every function in the call stack starting after | |
609 | ;; `completing-read' until to the first | |
610 | ;; `funcall-interactively' (for a call from the function | |
611 | ;; body) or `call-interactively' (for a call from the | |
612 | ;; interactive form, in which the function hasn't actually | |
613 | ;; been called yet, so `funcall-interactively' won't be on | |
614 | ;; the stack.) | |
615 | (cl-loop for i upfrom 1 | |
616 | for caller = (cadr (backtrace-frame i 'completing-read)) | |
617 | while caller | |
618 | while (not (memq (indirect-function caller) | |
619 | '(internal--funcall-interactively | |
620 | (indirect-function 'call-interactively)))) | |
621 | ||
622 | if (ido-cr+-function-is-blacklisted caller) | |
623 | do (signal 'ido-cr+-fallback | |
624 | (list (if (symbolp caller) | |
625 | (format "calling function `%S' is blacklisted" caller) | |
626 | "a calling function is blacklisted"))) | |
627 | ||
628 | if (and (not whitelisted) | |
629 | (ido-cr+-function-is-whitelisted caller)) | |
630 | do (progn | |
631 | (ido-cr+--debug-message | |
632 | (if (symbolp caller) | |
633 | (format "Calling function `%S' is whitelisted" caller) | |
634 | "A calling function is whitelisted")) | |
635 | (setq whitelisted t)) | |
636 | ||
637 | if (and require-match (null def) (not alt-nil-def) | |
638 | (ido-cr+-function-is-in-list | |
639 | caller ido-cr+-nil-def-alternate-behavior-list)) | |
640 | do (progn | |
641 | (ido-cr+--debug-message | |
642 | (if (symbolp caller) | |
643 | (format "Using alternate nil DEF handling for calling function `%S'" caller) | |
644 | "Using alternate nil DEF handling for a calling function")) | |
645 | (setq alt-nil-def t)))) | |
646 | ||
647 | (unless whitelisted | |
648 | (signal 'ido-cr+-fallback | |
649 | (list "no functions or commands matched the whitelist for this call"))) | |
650 | ||
651 | (when (and require-match (null def)) | |
652 | ;; Replace nil with "" for DEF if match is required, unless | |
653 | ;; alternate nil DEF handling is enabled | |
654 | (if alt-nil-def | |
655 | (ido-cr+--debug-message | |
656 | "Leaving the default at nil because alternate nil DEF handling is enabled.") | |
657 | (ido-cr+--debug-message | |
658 | "Adding \"\" as the default completion since no default was provided.") | |
659 | (setq def (list "")))) | |
660 | ||
661 | ;; In ido, the semantics of "default" are simply "put it at | |
662 | ;; the front of the list". Furthermore, ido can't handle a | |
663 | ;; list of defaults, nor can it handle both DEF and | |
664 | ;; INITIAL-INPUT being non-nil. So, just pre-process the | |
665 | ;; collection to put the default(s) at the front and then | |
666 | ;; set DEF to nil in the call to ido to avoid these issues. | |
667 | (unless (listp def) | |
668 | ;; Ensure DEF is a list | |
669 | (setq def (list def))) | |
670 | (when def | |
671 | ;; Ensure DEF are strings | |
672 | (setq def (mapcar (apply-partially #'format "%s") def)) | |
673 | ;; Prepend DEF to COLLECTION and remove duplicates | |
674 | (setq collection (delete-dups (append def collection)) | |
675 | def nil)) | |
676 | ||
677 | ;; Check for a specific bug | |
678 | (when (and ido-enable-dot-prefix | |
679 | (version< emacs-version "26.1") | |
680 | (member "" collection)) | |
681 | (signal 'ido-cr+-fallback | |
682 | '("ido cannot handle the empty string as an option when `ido-enable-dot-prefix' is non-nil; see https://debbugs.gnu.org/cgi/bugreport.cgi?bug=26997"))) | |
683 | ||
684 | ;; Fix ido handling of cons-style INITIAL-INPUT. TODO add a | |
685 | ;; version check after this bug is fixed: | |
686 | ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27807 | |
687 | (when (consp initial-input) | |
688 | ;; `completing-read' uses 0-based index while | |
689 | ;; `read-from-minibuffer' uses 1-based index. | |
690 | (cl-incf (cdr initial-input))) | |
691 | ||
692 | ;; Finally ready to do actual ido completion | |
211 | 693 | (prog1 |
212 | (let ((ido-cr+-enable-next-call t)) | |
213 | (ido-completing-read | |
214 | prompt collection | |
215 | predicate require-match initial-input hist def | |
216 | inherit-input-method)) | |
694 | (let ((ido-cr+-minibuffer-depth (1+ (minibuffer-depth))) | |
695 | ;; Initialize dynamic update vars | |
696 | (ido-cr+-previous-dynamic-update-texts | |
697 | (list initial-input-string)) | |
698 | (ido-cr+-dynamic-update-timer nil) | |
699 | (ido-cr+-exhibit-pending t) | |
700 | ;; Reset these for the next call to ido-cr+ | |
701 | (ido-cr+-no-default-action 'prepend-empty-string) | |
702 | (ido-cr+-assume-static-collection nil)) | |
703 | (unwind-protect | |
704 | (ido-completing-read | |
705 | prompt collection | |
706 | predicate require-match initial-input hist def | |
707 | inherit-input-method) | |
708 | (when ido-cr+-dynamic-update-timer | |
709 | (cancel-timer ido-cr+-dynamic-update-timer) | |
710 | (setq ido-cr+-dynamic-update-timer nil)))) | |
217 | 711 | ;; This detects when the user triggered fallback mode |
218 | 712 | ;; manually. |
219 | 713 | (when (eq ido-exit 'fallback) |
220 | 714 | (signal 'ido-cr+-fallback '("user manually triggered fallback"))))) |
715 | ||
221 | 716 | ;; Handler for ido-cr+-fallback signal |
222 | 717 | (ido-cr+-fallback |
223 | (ido-cr+--explain-fallback sig) | |
224 | (apply ido-cr+-fallback-function orig-args))))) | |
718 | (let (;; Reset `minibuffer-setup-hook' to original value | |
719 | (minibuffer-setup-hook orig-minibuffer-setup-hook) | |
720 | ;; Reset these for the next call to ido-cr+ | |
721 | (ido-cr+-no-default-action 'prepend-empty-string) | |
722 | (ido-cr+-assume-static-collection nil)) | |
723 | (ido-cr+--explain-fallback sig) | |
724 | (apply ido-cr+-fallback-function ido-cr+-orig-completing-read-args)))))) | |
225 | 725 | |
226 | 726 | ;;;###autoload |
227 | (defadvice ido-completing-read (around ido-cr+ activate) | |
228 | "This advice handles application of ido-completing-read+ features. | |
229 | ||
230 | First, it ensures that `ido-cr+-enable-this-call' is set | |
231 | properly. This variable should be non-nil during execution of | |
232 | `ido-completing-read' if it was called from | |
233 | `ido-completing-read+'. | |
234 | ||
235 | Second, if `ido-cr+-replace-completely' is non-nil, then this | |
236 | advice completely replaces `ido-completing-read' with | |
237 | `ido-completing-read+'." | |
727 | (defun ido-completing-read@ido-cr+-replace (orig-fun &rest args) | |
728 | "This advice allows ido-cr+ to completely replace `ido-completing-read'. | |
729 | ||
730 | See the varaible `ido-cr+-replace-completely' for more information." | |
238 | 731 | ;; If this advice is autoloaded, then we need to force loading of |
239 | 732 | ;; the rest of the file so all the variables will be defined. |
240 | 733 | (when (not (featurep 'ido-completing-read+)) |
241 | 734 | (require 'ido-completing-read+)) |
242 | (let ((ido-cr+-enable-this-call ido-cr+-enable-next-call) | |
243 | (ido-cr+-enable-next-call nil)) | |
244 | (if (or | |
245 | ido-cr+-enable-this-call ; Avoid recursion | |
246 | (not ido-cr+-replace-completely)) | |
247 | ad-do-it | |
248 | (message "Replacing ido-completing-read") | |
249 | (setq ad-return-value (apply #'ido-completing-read+ (ad-get-args 0)))))) | |
735 | (if (or (ido-cr+-active) | |
736 | (not ido-cr+-replace-completely)) | |
737 | ;; ido-cr+ has either already activated or isn't going to | |
738 | ;; activate, so just run the function as normal | |
739 | (apply orig-fun args) | |
740 | ;; Otherwise, we need to activate ido-cr+. | |
741 | (apply #'ido-completing-read+ args))) | |
742 | ;;;###autoload | |
743 | (advice-add 'ido-completing-read :around | |
744 | #'ido-completing-read@ido-cr+-replace) | |
745 | ||
746 | ;;;###autoload | |
747 | (defun call-interactively@ido-cr+-record-current-command | |
748 | (orig-fun command &rest args) | |
749 | "Let-bind the command being interactively called. | |
750 | ||
751 | See `ido-cr+-current-command' for more information." | |
752 | (let ((ido-cr+-current-command command)) | |
753 | (apply orig-fun command args))) | |
754 | ;;;###autoload | |
755 | (advice-add 'call-interactively :around | |
756 | #'call-interactively@ido-cr+-record-current-command) | |
250 | 757 | |
251 | 758 | ;; Fallback on magic C-f and C-b |
252 | ;;;###autoload | |
253 | (defvar ido-context-switch-command nil | |
254 | "Variable holding the command used for switching to another completion mode. | |
255 | ||
256 | This variable is originally declared in `ido.el', but it is not | |
257 | given a value (or a docstring). This documentation comes from a | |
258 | re-declaration in `ido-completing-read+.el' that initializes it | |
259 | to nil, which should suppress some byte-compilation warnings in | |
260 | Emacs 25. Setting another package's variable is not safe in | |
261 | general, but in this case it should be, because ido always | |
262 | let-binds this variable before using it, so the initial value | |
263 | shouldn't matter.") | |
264 | ||
265 | (defadvice ido-magic-forward-char (before ido-cr+-fallback activate) | |
759 | (defun ido-magic-forward-char@ido-cr+-fallback (&rest args) | |
266 | 760 | "Allow falling back in ido-completing-read+." |
267 | (when ido-cr+-enable-this-call | |
761 | (when (ido-cr+-active) | |
268 | 762 | ;; `ido-context-switch-command' is already let-bound at this |
269 | 763 | ;; point. |
270 | 764 | (setq ido-context-switch-command #'ido-fallback-command))) |
271 | ||
272 | (defadvice ido-magic-backward-char (before ido-cr+-fallback activate) | |
765 | (advice-add 'ido-magic-forward-char :before | |
766 | #'ido-magic-forward-char@ido-cr+-fallback) | |
767 | ||
768 | (defun ido-magic-backward-char@ido-cr+-fallback (&rest args) | |
273 | 769 | "Allow falling back in ido-completing-read+." |
274 | (when ido-cr+-enable-this-call | |
770 | (when (ido-cr+-active) | |
275 | 771 | ;; `ido-context-switch-command' is already let-bound at this |
276 | 772 | ;; point. |
277 | 773 | (setq ido-context-switch-command #'ido-fallback-command))) |
278 | ||
279 | ;;; Workaround for https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/93 | |
280 | ||
281 | (defadvice ido-select-text (around fix-require-match-behavior activate) | |
774 | (advice-add 'ido-magic-backward-char :before | |
775 | #'ido-magic-backward-char@ido-cr+-fallback) | |
776 | ||
777 | (defun ido-select-text@ido-cr+-fix-require-match (orig-fun &rest args) | |
282 | 778 | "Fix ido behavior when `require-match' is non-nil. |
283 | 779 | |
284 | 780 | Standard ido will allow C-j to exit with an incomplete completion |
286 | 782 | not allow this. In ordinary completion, RET on an incomplete |
287 | 783 | match is equivalent to TAB, and C-j selects the first match. |
288 | 784 | Since RET in ido already selects the first match, this advice |
289 | sets up C-j to be equivalent to TAB in the same situation." | |
785 | sets up C-j to be equivalent to TAB in the same situation. | |
786 | ||
787 | This advice only activates if the current ido completion was | |
788 | called through ido-cr+." | |
290 | 789 | (if (and |
291 | 790 | ;; Only override C-j behavior if... |
292 | ;; We're using ico-cr+ | |
293 | ido-cr+-enable-this-call | |
294 | ;; Require-match is non-nil | |
295 | (with-no-warnings ido-require-match) | |
296 | ;; A default was provided, or ido-text is non-empty | |
297 | (or (with-no-warnings ido-default-item) | |
298 | (not (string= ido-text ""))) | |
299 | ;; Only if current text is not a complete choice | |
300 | (not (member ido-text (with-no-warnings ido-cur-list)))) | |
791 | ;; We're using ico-cr+, and... | |
792 | (ido-cr+-active) | |
793 | ;; Require-match is non-nil, and... | |
794 | ido-require-match | |
795 | ;; The current input doesn't exactly match a known option, and... | |
796 | (not (member ido-text ido-cur-list)) | |
797 | ;; The current input doesn't exactly match an option according | |
798 | ;; to `try-completion' (or the collection is not dynamic). | |
799 | (or (not ido-cr+-dynamic-collection) | |
800 | (eq t (try-completion ido-text ido-cr+-dynamic-collection | |
801 | (nth 2 ido-cr+-orig-completing-read-args))))) | |
301 | 802 | (progn |
302 | 803 | (ido-cr+--debug-message |
303 | 804 | "Overriding C-j behavior for require-match: performing completion instead of exiting with current text. (This might still exit with a match if `ido-confirm-unique-completion' is nil)") |
304 | 805 | (ido-complete)) |
305 | ad-do-it)) | |
806 | (apply orig-fun args))) | |
807 | (advice-add 'ido-select-text :around | |
808 | #'ido-select-text@ido-cr+-fix-require-match) | |
809 | ||
810 | (defun ido-tidy@ido-cr+-set-exhibit-pending (&rest args) | |
811 | (setq ido-cr+-exhibit-pending t)) | |
812 | (advice-add 'ido-tidy :after 'ido-tidy@ido-cr+-set-exhibit-pending) | |
813 | ||
814 | (defun ido-exhibit@ido-cr+-clear-exhibit-pending (&rest args) | |
815 | (setq ido-cr+-exhibit-pending nil)) | |
816 | (advice-add 'ido-exhibit :before 'ido-exhibit@ido-cr+-clear-exhibit-pending) | |
817 | ||
818 | (defun ido-cr+-all-prefix-completions | |
819 | (string collection &optional predicate) | |
820 | "Run `all-completions' on every prefix of STRING. | |
821 | ||
822 | Arguments COLLECTION and PREDICATE are as in `all-completions'. | |
823 | Note that \"all prefixes\" includes both STRING itself and the | |
824 | empty string. The return value is the union of all the returned | |
825 | lists, with elements ordered by their first occurrence. | |
826 | ||
827 | This function is only useful if COLLECTION is a function that | |
828 | might return additional completions for certain non-empty strings | |
829 | that it wouldn't return for the empty string. If COLLECTION is | |
830 | not a function, this is equivalent to | |
831 | `(all-completions \"\" COLELCTION PREDICATE)'." | |
832 | (cond | |
833 | ;; Dynamic collection. | |
834 | ((functionp collection) | |
835 | ;; Collect completions for all prefixes of STRING starting from | |
836 | ;; "". | |
837 | (cl-loop | |
838 | for i from 0 upto (length string) | |
839 | append (funcall | |
840 | (or ido-cr+-all-completions-memoized | |
841 | 'all-completions) | |
842 | (s-left i string) | |
843 | collection | |
844 | predicate) | |
845 | into completion-list | |
846 | finally return (delete-dups completion-list))) | |
847 | ;; Otherwise, just call `all-completions' on the empty string to | |
848 | ;; get every possible completions for a static COLLECTION. | |
849 | (t | |
850 | (all-completions "" collection predicate)))) | |
851 | ||
852 | (defun ido-cr+-apply-restrictions (collection restrictions) | |
853 | "Filter COLLECTION through RESTRICTIONS in sequence. | |
854 | ||
855 | COLLECTION is a list of strings. RESTRICTIONS is a list of cons | |
856 | cells, with the cdr being the restriction text and the car being | |
857 | nil to include matches for that text and t to exclude matches for | |
858 | that text. The return value is a list of strings that satisfy all | |
859 | the restrictions, in the same order as they appeared in | |
860 | COLLECTION. | |
861 | ||
862 | RESTRICTIONS are applied one by one in order, which is important | |
863 | because in theory the order can make a difference to the final | |
864 | result." | |
865 | (cl-loop | |
866 | with filtered-collection = collection | |
867 | with need-reverse = nil | |
868 | for (removep . text) in restrictions | |
869 | for restriction-matches = | |
870 | (let ((ido-text text) | |
871 | (ido-cur-item (or ido-cur-item 'list))) | |
872 | (ido-set-matches-1 filtered-collection t)) | |
873 | do (setq filtered-collection | |
874 | (if removep | |
875 | (seq-difference filtered-collection restriction-matches) | |
876 | (setq need-reverse (not need-reverse)) | |
877 | restriction-matches)) | |
878 | ;; Each run of `ido-set-matches-1' reverses the order, so reverse | |
879 | ;; it one more time if it had an odd number of reverses | |
880 | finally return | |
881 | (if need-reverse | |
882 | (nreverse filtered-collection) | |
883 | filtered-collection))) | |
884 | ||
885 | (defun ido-cr+-update-dynamic-collection () | |
886 | "Update the set of completions for a dynamic collection. | |
887 | ||
888 | This has no effect unless `ido-cr+-dynamic-collection' is non-nil." | |
889 | (when (and (ido-cr+-active) | |
890 | ido-cr+-dynamic-collection) | |
891 | (let* ((ido-text | |
892 | (buffer-substring-no-properties (minibuffer-prompt-end) | |
893 | ido-eoinput)) | |
894 | (predicate (nth 2 ido-cr+-orig-completing-read-args)) | |
895 | (first-match (car ido-matches)) | |
896 | (strings-to-check | |
897 | (cond | |
898 | ;; If no match, then we only check `ido-text' | |
899 | ((null first-match) | |
900 | (list ido-text)) | |
901 | ;; If `ido-text' is a prefix of `first-match', then we | |
902 | ;; only need to check `first-match' | |
903 | ((and first-match | |
904 | (s-prefix? ido-text first-match)) | |
905 | (list first-match)) | |
906 | ;; Otherwise we need to check both | |
907 | (t | |
908 | (list ido-text first-match)))) | |
909 | (new-completions | |
910 | (cl-loop | |
911 | for string in strings-to-check | |
912 | nconc | |
913 | (funcall | |
914 | (or ido-cr+-all-prefix-completions-memoized | |
915 | 'ido-cr+-all-prefix-completions) | |
916 | string ido-cr+-dynamic-collection predicate) | |
917 | into result | |
918 | finally return result))) | |
919 | (when new-completions | |
920 | (setq ido-cur-list (delete-dups new-completions)) | |
921 | (when ido-cr+-active-restrictions | |
922 | (setq ido-cur-list (ido-cr+-apply-restrictions | |
923 | ido-cur-list | |
924 | ido-cr+-active-restrictions))) | |
925 | (when (and first-match (member first-match ido-cur-list)) | |
926 | (setq ido-cur-list (ido-chop ido-cur-list first-match))) | |
927 | (ido-cr+--debug-message | |
928 | "Updated completion candidates for dynamic collection because `ido-text' changed to %S. `ido-cur-list' now has %s elements" | |
929 | ido-text (length ido-cur-list)) | |
930 | ;; Recompute matches with new completions | |
931 | (setq ido-rescan t) | |
932 | (ido-set-matches) | |
933 | ;; Rebuild the completion display unless ido is already planning | |
934 | ;; to do it anyway | |
935 | (unless ido-cr+-exhibit-pending | |
936 | (ido-tidy) | |
937 | (ido-exhibit))))) | |
938 | ;; Always cancel an active timer when this function is called. | |
939 | (when ido-cr+-dynamic-update-timer | |
940 | (cancel-timer ido-cr+-dynamic-update-timer) | |
941 | (setq ido-cr+-dynamic-update-timer nil))) | |
942 | ||
943 | (defun ido-cr+-schedule-dynamic-collection-update () | |
944 | "Schedule a dynamic collection update for now or in the future." | |
945 | (when (and (ido-cr+-active) | |
946 | ido-cr+-dynamic-collection) | |
947 | ;; Cancel the previous timer | |
948 | (when ido-cr+-dynamic-update-timer | |
949 | (cancel-timer ido-cr+-dynamic-update-timer) | |
950 | (setq ido-cr+-dynamic-update-timer nil)) | |
951 | (if (<= (length ido-matches) 1) | |
952 | ;; If we've narrowed it down to zero or one matches, update | |
953 | ;; immediately. | |
954 | (ido-cr+-update-dynamic-collection) | |
955 | ;; If there are still several choices, defer update until idle | |
956 | (setq ido-cr+-dynamic-update-timer | |
957 | (run-with-idle-timer (max 0.01 ido-cr+-dynamic-update-idle-time) nil | |
958 | #'ido-cr+-update-dynamic-collection))))) | |
959 | ||
960 | (defun ido-cr+-minibuffer-setup () | |
961 | "set up minibuffer `post-command-hook' for ido-cr+ " | |
962 | (when (ido-cr+-active) | |
963 | (add-hook 'post-command-hook | |
964 | 'ido-cr+-schedule-dynamic-collection-update))) | |
965 | (add-hook 'ido-minibuffer-setup-hook | |
966 | 'ido-cr+-minibuffer-setup) | |
967 | ||
968 | ;; Also need to update dynamic collections on TAB, and do so *before* | |
969 | ;; deciding to exit based on `ido-confirm-unique-completion' | |
970 | (defun ido-complete@ido-cr+-update-dynamic-collection (oldfun &rest args) | |
971 | "Maybe update the set of completions when pressing TAB." | |
972 | (when ido-cr+-dynamic-collection | |
973 | ;; First run with `ido-confirm-unique-completion' non-nil so it | |
974 | ;; can't exit | |
975 | (let ((ido-confirm-unique-completion t)) | |
976 | (apply oldfun args)) | |
977 | ;; Update `ido-eoinput' | |
978 | (setq ido-eoinput (point-max)) | |
979 | ;; Now do update | |
980 | (ido-cr+-update-dynamic-collection)) | |
981 | ;; After maybe updating the dynamic collection, if there's still | |
982 | ;; only one completion, now it's allowed to exit | |
983 | (apply oldfun args)) | |
984 | (advice-add 'ido-complete :around 'ido-complete@ido-cr+-update-dynamic-collection) | |
985 | ||
986 | ;; When using `ido-restrict-to-matches', we also need to add an | |
987 | ;; equivalent predicate to the dynamic collection so that | |
988 | ;; dynamically-added completions are also properly restricted. | |
989 | (defun ido-restrict-to-matches@ido-cr+-record-restriction | |
990 | (&optional removep) | |
991 | "Record the restriction criterion for ido-cr+" | |
992 | (ido-cr+--debug-message "Appending restriction %S to `ido-cr+-active-restrictions'" | |
993 | (cons removep ido-text)) | |
994 | (add-to-list 'ido-cr+-active-restrictions (cons removep ido-text) t)) | |
995 | (advice-add 'ido-restrict-to-matches :before | |
996 | 'ido-restrict-to-matches@ido-cr+-record-restriction) | |
997 | ||
998 | ;; Interoperation with minibuffer-electric-default-mode: only show the | |
999 | ;; default when the input is empty and the empty string is the | |
1000 | ;; selected choice | |
1001 | (defun minibuf-eldef-update-minibuffer@ido-cr+-compat (orig-fun &rest args) | |
1002 | "This advice allows minibuffer-electric-default-mode to work with ido-cr+." | |
1003 | (if (ido-cr+-active) | |
1004 | (unless (eq minibuf-eldef-showing-default-in-prompt | |
1005 | (and (string= (car ido-cur-list) "") | |
1006 | (string= ido-text ""))) | |
1007 | ;; Swap state. | |
1008 | (setq minibuf-eldef-showing-default-in-prompt | |
1009 | (not minibuf-eldef-showing-default-in-prompt)) | |
1010 | (overlay-put minibuf-eldef-overlay 'invisible | |
1011 | (not minibuf-eldef-showing-default-in-prompt))) | |
1012 | (apply orig-fun args))) | |
1013 | (advice-add 'minibuf-eldef-update-minibuffer :around | |
1014 | #'minibuf-eldef-update-minibuffer@ido-cr+-compat) | |
1015 | ||
1016 | ;;;###autoload | |
1017 | (define-minor-mode ido-ubiquitous-mode | |
1018 | "Use ido completion instead of standard completion almost everywhere. | |
1019 | ||
1020 | If this mode causes problems for a function, you can customize | |
1021 | when ido completion is or is not used by customizing | |
1022 | `ido-cr+-function-blacklist'." | |
1023 | nil | |
1024 | :global t | |
1025 | :group 'ido-completing-read-plus | |
1026 | ;; Actually enable/disable the mode by setting | |
1027 | ;; `completing-read-function'. | |
1028 | (setq completing-read-function | |
1029 | (if ido-ubiquitous-mode | |
1030 | #'ido-completing-read+ | |
1031 | ido-cr+-fallback-function))) | |
1032 | ||
1033 | (defcustom ido-cr+-auto-update-blacklist 'notify | |
1034 | "Whether to add new overrides when updating ido-cr+. | |
1035 | ||
1036 | This variable has 3 possible values, with the following meanings: | |
1037 | ||
1038 | `t': Auto-update the blacklist | |
1039 | `notify': Notify you about updates but do not apply them | |
1040 | `nil': Ignore all blacklist updates | |
1041 | ||
1042 | Ido-cr+ comes with a default blacklist for commands that are | |
1043 | known to be incompatible with ido completion. New versions of | |
1044 | ido-cr+ may come with updates to this blacklist as more | |
1045 | incompatible commands are discovered. However, customizing your | |
1046 | own overrides would normally prevent you from receiving these | |
1047 | updates, since Emacs will not overwrite your customizations. | |
1048 | ||
1049 | To resolve this problem, you can set this variable to `t', and | |
1050 | then ido-cr+ can automatically add any new built-in overrides | |
1051 | whenever it is updated. (Actually, the update will happen the | |
1052 | next time Emacs is restarted after the update.) This allows you | |
1053 | to add your own overrides but still receive updates to the | |
1054 | default set. | |
1055 | ||
1056 | If you want ido-cr+ to just notify you about new default | |
1057 | overrides instead of adding them itself, set this variable to | |
1058 | `notify'. If you don't want this auto-update behavior at all, set | |
1059 | it to `nil'. | |
1060 | ||
1061 | (Note that having this option enabled effectively prevents you | |
1062 | from removing any of the built-in default blacklist entries, | |
1063 | since they will simply be re-added the next time Emacs starts.)" | |
1064 | :type '(choice :tag "When new overrides are available:" | |
1065 | (const :menu-tag "Auto-add" | |
1066 | :tag "Add them automatically" | |
1067 | t) | |
1068 | (const :menu-tag "Notify" | |
1069 | :tag "Notify me about them" | |
1070 | notify) | |
1071 | (const :menu-tag "Ignore" | |
1072 | :tag "Ignore them" | |
1073 | nil)) | |
1074 | :group 'ido-completing-read-plus) | |
1075 | ||
1076 | (defun ido-cr+-update-blacklist (&optional save quiet) | |
1077 | "Re-add any missing default blacklist entries. | |
1078 | ||
1079 | This is useful after an update of ido-ubiquitous that adds new | |
1080 | default overrides. See `ido-cr+-auto-update-blacklist' for more | |
1081 | information. | |
1082 | ||
1083 | If SAVE is non-nil, also save the new blacklist to the user's | |
1084 | Custom file (but only if it was already customized beforehand). | |
1085 | When called interactively, a prefix argument triggers a save. | |
1086 | ||
1087 | When called from Lisp code, this function returns non-nil if the | |
1088 | blacklist was modified." | |
1089 | (interactive "P") | |
1090 | (let* ((var-state (custom-variable-state 'ido-cr+-function-blacklist | |
1091 | ido-cr+-function-blacklist)) | |
1092 | (curval ido-cr+-function-blacklist) | |
1093 | (defval (eval (car (get 'ido-cr+-function-blacklist 'standard-value)))) | |
1094 | (newval (delete-dups (append defval curval))) | |
1095 | (new-entries (cl-set-difference defval curval :test #'equal)) | |
1096 | (modified nil) | |
1097 | (saved nil) | |
1098 | (message-lines ())) | |
1099 | (cl-case var-state | |
1100 | (standard | |
1101 | ;; Var is not customized, just set the new default | |
1102 | (ido-cr+--debug-message "Blacklist was not customized, so it has been updated to the new default value.") | |
1103 | (setq ido-cr+-function-blacklist defval | |
1104 | modified new-entries)) | |
1105 | ((saved set changed) | |
1106 | ;; Var has been customized and saved by the user, so set the | |
1107 | ;; new value and maybe save it | |
1108 | (ido-cr+--debug-message "Updating user-customized blacklist with new default entries.") | |
1109 | (setq ido-cr+-function-blacklist newval | |
1110 | modified t) | |
1111 | (when (and save (eq var-state 'saved)) | |
1112 | (ido-cr+--debug-message "Saving new blacklist value to Custom file.") | |
1113 | (customize-save-variable 'ido-cr+-function-blacklist ido-cr+-function-blacklist) | |
1114 | (setq saved t))) | |
1115 | (otherwise | |
1116 | (ido-cr+--debug-message "Customization status of blacklist is unknown. Not modifying it."))) | |
1117 | (if (and modified (not quiet)) | |
1118 | (progn | |
1119 | (push (format "Added the following entries to `ido-cr+-function-blacklist': %S" new-entries) | |
1120 | message-lines) | |
1121 | (if saved | |
1122 | (push "Saved the new value of `ido-cr+-function-blacklist' to your Custom file." | |
1123 | message-lines) | |
1124 | (push "However, the new value of `ido-cr+-function-blacklist' has not yet been saved for future sessions. To save it. re-run this command with a prefix argument: `C-u M-x ido-cr+-update-blacklist'; or else manually inspect and save the value using `M-x customize-variable ido-cr+-function-blacklist'." | |
1125 | message-lines))) | |
1126 | (push "No updates were required to `ido-cr+-function-blacklist'." message-lines)) | |
1127 | (unless quiet | |
1128 | (message (mapconcat #'identity (nreverse message-lines) "\n"))) | |
1129 | modified)) | |
1130 | ||
1131 | (defun ido-cr+-maybe-update-blacklist () | |
1132 | "Maybe call `ico-cr+-update-blacklist. | |
1133 | ||
1134 | See `ido-cr+-auto-update-blacklist' for more information." | |
1135 | (if ido-cr+-auto-update-blacklist | |
1136 | (let* ((curval ido-cr+-function-blacklist) | |
1137 | (defval (eval (car (get 'ido-cr+-function-blacklist 'standard-value)))) | |
1138 | (new-entries (cl-set-difference curval defval :test #'equal))) | |
1139 | (if new-entries | |
1140 | (if (eq ido-cr+-auto-update-blacklist 'notify) | |
1141 | (display-warning 'ido-completing-read+ "There are %s new blacklist entries available. Use `M-x ido-cr+-update-blacklist' to install them. (See `ido-cr+-auto-update-blacklist' for more information.)") | |
1142 | (ido-cr+--debug-message "Initiating blacklist update.") | |
1143 | (ido-cr+-update-blacklist t)) | |
1144 | (ido-cr+--debug-message "No blacklist updates available."))) | |
1145 | (ido-cr+--debug-message "Skipping blacklist update by user request."))) | |
1146 | ||
1147 | (ido-cr+-maybe-update-blacklist) | |
306 | 1148 | |
307 | 1149 | (provide 'ido-completing-read+) |
308 | 1150 |
0 | 0 | ;;; ido-ubiquitous.el --- Use ido (nearly) everywhere. -*- lexical-binding: t -*- |
1 | 1 | |
2 | ;; Copyright (C) 2011-2015 Ryan C. Thompson | |
2 | ;; Copyright (C) 2011-2017 Ryan C. Thompson | |
3 | 3 | |
4 | 4 | ;; Author: Ryan C. Thompson |
5 | 5 | ;; URL: https://github.com/DarwinAwardWinner/ido-ubiquitous |
6 | ;; Version: 3.16 | |
6 | ;; Version: 4.5 | |
7 | 7 | ;; Created: 2011-09-01 |
8 | 8 | ;; Keywords: convenience, completion, ido |
9 | 9 | ;; EmacsWiki: InteractivelyDoThings |
10 | ;; Package-Requires: ((emacs "24.1") (ido-completing-read+ "3.16") (cl-lib "0.5")) | |
10 | ;; Package-Requires: ((emacs "24.1") (ido-completing-read+ "4.5") (cl-lib "0.5")) | |
11 | 11 | ;; Filename: ido-ubiquitous.el |
12 | 12 | |
13 | 13 | ;; This file is NOT part of GNU Emacs. |
16 | 16 | ;; |
17 | 17 | ;;; Commentary: |
18 | 18 | |
19 | ;; If you use the excellent `ido-mode' for efficient completion of | |
20 | ;; file names and buffers, you might wonder if you can get ido-style | |
21 | ;; completion everywhere else too. Well, that's what this package | |
22 | ;; does! ido-ubiquitous is here to enable ido-style completion for | |
23 | ;; (almost) every function that uses the standard completion function | |
24 | ;; `completing-read'. | |
25 | ||
26 | ;; To use this package, call `ido-ubiquitous-mode' to enable the mode, | |
27 | ;; or use `M-x customize-variable ido-ubiquitous-mode' it to enable it | |
28 | ;; permanently. Once the mode is enabled, most functions that use | |
29 | ;; `completing-read' will now have ido completion. If you decide in | |
30 | ;; the middle of a command that you would rather not use ido, just C-f | |
31 | ;; or C-b at the end/beginning of the input to fall back to non-ido | |
32 | ;; completion (this is the same shortcut as when using ido for buffers | |
33 | ;; or files). | |
34 | ||
35 | ;; Note that `completing-read' has some quirks and complex behavior | |
36 | ;; that ido cannot emulate. Ido-ubiquitous attempts to detect some of | |
37 | ;; these quirks and avoid using ido when it sees them. So some | |
38 | ;; functions will not have ido completion even when this mode is | |
39 | ;; enabled. Some other functions have ido disabled in them because | |
40 | ;; their packages already provide support for ido via other means (for | |
41 | ;; example, magit). See `M-x customize-group ido-ubiquitous' and read | |
42 | ;; about the override variables for more information. | |
43 | ||
44 | ;; ido-ubiquitous version 3.0 is a major update, including a split | |
45 | ;; into two packages, and some of the configuration options have | |
46 | ;; changed in non-backwards-compatible ways. If you have customized | |
47 | ;; ido-ubiquitous, be sure to check out `M-x customize-group | |
48 | ;; ido-ubiquitous' and `M-x customize-group ido-completing-read+' | |
49 | ;; after updating to 3.0 and make sure the new settings are to your | |
50 | ;; liking. | |
19 | ;; Previously a separate package, ido-ubiquitous has now been subsumed | |
20 | ;; into ido-completing-read+. You should update your config to install that instead. | |
51 | 21 | |
52 | 22 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
53 | 23 | ;; |
68 | 38 | ;; |
69 | 39 | ;;; Code: |
70 | 40 | |
71 | (defconst ido-ubiquitous-version "3.16" | |
41 | (defconst ido-ubiquitous-version "4.5" | |
72 | 42 | "Currently running version of ido-ubiquitous. |
73 | 43 | |
74 | 44 | Note that when you update ido-ubiquitous, this variable may not |
75 | 45 | be updated until you restart Emacs.") |
76 | 46 | |
77 | (eval-when-compile | |
78 | (when (or (not (boundp 'completing-read-function)) | |
79 | (< emacs-major-version 24)) | |
80 | (error "Could not find required variable `completing-read-function'. Are you using Emacs version 24 or higher? If you have Emacs 23 or lower, please downgrade to ido-ubiquitous version 1.7 (or upgrade Emacs)."))) | |
81 | ||
82 | (require 'ido) | |
83 | (require 'advice) | |
84 | (require 'cl-lib) | |
85 | (require 'cus-edit) | |
86 | 47 | (require 'ido-completing-read+) |
87 | 48 | |
88 | ;; Only exists in emacs 24.4 and up; we don't use this library | |
89 | ;; directly, but we load it here so we can test if it's available, | |
90 | ;; because if it isn't we need enable a workaround. | |
91 | (require 'nadvice nil 'noerror) | |
49 | (display-warning 'ido-ubiquitous "The ido-ubiquitous package is now redundant. All functionality, including ido-ubiquitous-mode, has been merged into the ido-completing-read+ package. You should replace ido-ubiquitous with ido-completing-read+ in your Emacs config. For more information, see: | |
50 | https://github.com/DarwinAwardWinner/ido-ubiquitous#version-40-changes") | |
92 | 51 | |
93 | ;;; Debug messages | |
94 | ||
95 | ;;;###autoload | |
96 | (define-minor-mode ido-ubiquitous-debug-mode | |
97 | "If non-nil, ido-ubiquitous will print debug info. | |
98 | ||
99 | Debug info is printed to the *Messages* buffer." | |
100 | nil | |
101 | :global t | |
102 | :group 'ido-ubiquitous) | |
103 | ||
104 | (defun ido-ubiquitous--debug-message (format-string &rest args) | |
105 | (when ido-ubiquitous-debug-mode | |
106 | (apply #'message (concat "ido-ubiquitous: " format-string) args))) | |
107 | ||
108 | (defun ido-ubiquitous--explain-fallback (arg) | |
109 | ;; This function accepts a string, or an ido-ubiquitous-fallback | |
110 | ;; signal. | |
111 | (when ido-ubiquitous-debug-mode | |
112 | (when (and (listp arg) | |
113 | (eq (car arg) 'ido-ubiquitous-fallback)) | |
114 | (setq arg (cadr arg))) | |
115 | (ido-ubiquitous--debug-message "Falling back to `%s' because %s." | |
116 | ido-cr+-fallback-function arg))) | |
117 | ||
118 | ;;; Internal utility functions | |
119 | ||
120 | (defun ido-ubiquitous--as-string (sym-or-str) | |
121 | "Return name of symbol, return string as is." | |
122 | (if (symbolp sym-or-str) | |
123 | (symbol-name sym-or-str) | |
124 | sym-or-str)) | |
125 | ||
126 | (defun ido-ubiquitous--as-symbol (sym-or-str) | |
127 | "Return string as symbol, return symbol as is." | |
128 | (if (symbolp sym-or-str) | |
129 | sym-or-str | |
130 | (intern sym-or-str))) | |
131 | ||
132 | ;;; Custom widget definitions | |
133 | ||
134 | ;; We need to define some custom widget types for use in the override | |
135 | ;; variables. | |
136 | ||
137 | (define-widget 'lazy-notag 'lazy | |
138 | "Like lazy widget, but does not display its tag, only its value." | |
139 | :format "%v") | |
140 | ||
141 | ;; Define matcher functions and widgets for match specifications | |
142 | (defvar ido-ubiquitous-match-spec-widget-types nil | |
143 | "List of widget names for match specs.") | |
144 | (defvar ido-ubiquitous-spec-matchers nil | |
145 | "Alist of functions for matching function specs against function names.") | |
146 | (cl-loop for (widget-name widget-tag key field-type matcher) in | |
147 | '((exact-match "Exact match" exact string string=) | |
148 | (prefix-match "Prefix match" prefix string string-prefix-p) | |
149 | (regexp-match "Regexp match" regexp regexp string-match-p)) | |
150 | do (define-widget (ido-ubiquitous--as-symbol widget-name) 'lazy-notag widget-tag | |
151 | :menu-tag widget-tag | |
152 | :type `(list :tag ,widget-tag :format "%v" | |
153 | (const :format "" | |
154 | :tag ,widget-tag | |
155 | ,key) | |
156 | (,field-type :tag ,widget-tag))) | |
157 | do (add-to-list 'ido-ubiquitous-match-spec-widget-types | |
158 | widget-name 'append) | |
159 | do (add-to-list 'ido-ubiquitous-spec-matchers | |
160 | (cons key matcher) 'append)) | |
161 | ||
162 | (define-widget 'ido-ubiquitous-match-spec 'lazy-notag | |
163 | "Choice of exact, prefix, or regexp match." | |
164 | :type `(choice :tag "Match type" | |
165 | ,@ido-ubiquitous-match-spec-widget-types)) | |
166 | ||
167 | (define-widget 'ido-ubiquitous-command-override-spec 'lazy-notag | |
168 | "Choice of override action plus match specification." | |
169 | :type '(cons :tag "Override rule" | |
170 | (choice :tag "For matching commands" | |
171 | (const :menu-tag "Disable" | |
172 | :tag "Disable ido-ubiquitous" | |
173 | disable) | |
174 | (const :menu-tag "Enable" | |
175 | :tag "Enable ido-ubiquitous in normal default mode" | |
176 | enable) | |
177 | (const :menu-tag "Enable old-style default" | |
178 | :tag "Enable ido-ubiquitous in old-style default mode" | |
179 | enable-old)) | |
180 | ido-ubiquitous-match-spec)) | |
181 | ||
182 | (define-widget 'ido-ubiquitous-function-override-spec 'lazy-notag | |
183 | "Choice of override action and function name. (Exact match only.)" | |
184 | :type '(list :tag "Override rule" | |
185 | (choice :tag "Do the following" | |
186 | (const :menu-tag "Disable" | |
187 | :tag "Disable ido-ubiquitous" | |
188 | disable) | |
189 | (const :menu-tag "Enable" | |
190 | :tag "Enable ido-ubiquitous in normal default mode" | |
191 | enable) | |
192 | (const :menu-tag "Enable old-style default" | |
193 | :tag "Enable ido-ubiquitous in old-style default mode" | |
194 | enable-old)) | |
195 | (const :format "" exact) | |
196 | (string :tag "For function"))) | |
197 | ||
198 | ;;; Custom Declarations | |
199 | ||
200 | (defgroup ido-ubiquitous nil | |
201 | "Use ido for (almost) all completion." | |
202 | :group 'ido | |
203 | :group 'ido-completing-read-plus) | |
204 | ||
205 | ;;;###autoload | |
206 | (define-obsolete-variable-alias 'ido-ubiquitous | |
207 | 'ido-ubiquitous-mode "ido-ubiquitous 0.8") | |
208 | ;;;###autoload | |
209 | (define-obsolete-function-alias 'ido-ubiquitous | |
210 | 'ido-ubiquitous-mode "ido-ubiquitous 0.8") | |
211 | ||
212 | ;;;###autoload | |
213 | (define-minor-mode ido-ubiquitous-mode | |
214 | "Use `ido-completing-read' instead of `completing-read' almost everywhere. | |
215 | ||
216 | If this mode causes problems for a function, you can customize | |
217 | when ido completion is or is not used by customizing | |
218 | `ido-ubiquitous-command-overrides' or | |
219 | `ido-ubiquitous-function-overrides'." | |
220 | nil | |
221 | :global t | |
222 | :group 'ido-ubiquitous | |
223 | ;; Actually enable/disable the mode by setting | |
224 | ;; `completing-read-function'. | |
225 | (setq completing-read-function | |
226 | (if ido-ubiquitous-mode | |
227 | #'completing-read-ido-ubiquitous | |
228 | ido-cr+-fallback-function))) | |
229 | ||
230 | ;; Variables for functionality that has moved to ido-completing-read+ | |
231 | (define-obsolete-variable-alias | |
232 | 'ido-ubiquitous-max-items | |
233 | 'ido-cr+-max-items | |
234 | "ido-ubiquitous 3.0") | |
235 | (define-obsolete-variable-alias | |
236 | 'ido-ubiquitous-fallback-completing-read-function | |
237 | 'ido-cr+-fallback-function | |
238 | "ido-ubiquitous 3.0") | |
239 | ||
240 | (define-obsolete-variable-alias | |
241 | 'ido-ubiquitous-enable-compatibility-globally | |
242 | 'ido-ubiquitous-enable-old-style-default | |
243 | "ido-ubiquitous 2.0") | |
244 | ||
245 | (defcustom ido-ubiquitous-default-state 'enable | |
246 | "Default ido-ubiquitous mode of operation for commands with no override. | |
247 | ||
248 | This can be set to one of three options: | |
249 | ||
250 | * `enable': use normal ido completion; | |
251 | * `enable-old': use ido completion, but with emulation of the | |
252 | old-style default selection of `completing-read'; | |
253 | * `disable': use non-ido completion. | |
254 | ||
255 | Command-specific and function-specific overrides are available to | |
256 | override this default for specific commands/functions. See | |
257 | `ido-ubiquitous-command-overrides' and | |
258 | `ido-ubiquitous-function-overrides'. | |
259 | ||
260 | The `enable-old' option swaps the behavior of RET and C-j but | |
261 | only for the first keypress after beginning completion. | |
262 | Specifically, on the first keypress, RET will return an empty | |
263 | string and C-j will return the first item on the list. The | |
264 | purpose of this is to emulate a legacy compatibility quirk of | |
265 | `completing-read'. From the `completing-read' docstring: | |
266 | ||
267 | > If the input is null, `completing-read' returns DEF, or the | |
268 | > first element of the list of default values, or an empty string | |
269 | > if DEF is nil, regardless of the value of REQUIRE-MATCH. | |
270 | ||
271 | This odd behavior is required for compatibility with an old-style | |
272 | usage pattern whereby the default was requested by returning an | |
273 | empty string. In this mode, the caller receives the empty string | |
274 | and handles the default case manually, while `completing-read' | |
275 | never has any knowledge of the default. This is a problem for | |
276 | ido, which normally returns the first element in the list, not an | |
277 | empty string, when the input is empty and you press RET. Without | |
278 | knowledge of the default, it cannot ensure that the default is | |
279 | first on the list, so returning the first item is not the correct | |
280 | behavior. Instead, it must return an empty string like | |
281 | `completing-read'. | |
282 | ||
283 | The `disable' mode is available as a default, which seems | |
284 | counterintuitive. But this allows you, if you so desire, to | |
285 | enable ido-ubiquitous selectively for only a few specific commands | |
286 | using overrides and disable it for everything else." | |
287 | :type '(choice :tag "Default mode" | |
288 | (const :menu-tag "Disable" | |
289 | :tag "Disable ido-ubiquitous" | |
290 | disable) | |
291 | (const :menu-tag "Enable" | |
292 | :tag "Enable ido-ubiquitous in normal default mode" | |
293 | enable) | |
294 | (const :menu-tag "Enable old-style default" | |
295 | :tag "Enable ido-ubiquitous in old-style default mode" | |
296 | enable-old)) | |
297 | :group 'ido-ubiquitous) | |
52 | (define-obsolete-function-alias 'completing-read-ido-ubiquitous 'ido-completing-read+ | |
53 | "ido-completing-read+ 4.0") | |
54 | (define-obsolete-function-alias 'ido-ubiquitous-update-overrides 'ido-cr+-update-blacklist | |
55 | "ido-completing-read+ 4.0") | |
56 | (define-obsolete-function-alias 'ido-ubiquitous--maybe-update-overrides 'ido-cr+-maybe-update-blacklist | |
57 | "ido-completing-read+ 4.0") | |
58 | (define-obsolete-variable-alias 'ido-ubiquitous-auto-update-overrides 'ido-cr+-auto-update-blacklist | |
59 | "ido-completing-read+ 4.0") | |
298 | 60 | |
299 | 61 | (make-obsolete-variable |
300 | 'ido-ubiquitous-enable-old-style-default | |
301 | "This variable no longer has any effect. Set | |
302 | `ido-ubiquitous-default-state' to `enable-old' instead." | |
303 | "ido-ubiquitous 3.0") | |
304 | ||
305 | (defconst ido-ubiquitous-default-command-overrides | |
306 | '(;; If you want ido for M-x, install smex | |
307 | (disable exact "execute-extended-command") | |
308 | ;; Wanderlust uses new-style default | |
309 | (enable prefix "wl-") | |
310 | ;; Info functions use old-style default selection | |
311 | (enable-old prefix "Info-") | |
312 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/4 | |
313 | (enable exact "webjump") | |
314 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/28 | |
315 | (enable regexp "\\`\\(find\\|load\\|locate\\)-library\\'") | |
316 | ;; https://github.com/bbatsov/prelude/issues/488 | |
317 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/44 | |
318 | ;; tmm implements its own non-standard completion mechanics | |
319 | (disable prefix "tmm-") | |
320 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/47 | |
321 | ;; theme functions don't need old-style compatibility | |
322 | (enable regexp "\\`\\(load\\|enable\\|disable\\|describe\\|custom-theme-visit\\)-theme\\'") | |
323 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/79 | |
324 | (enable-old prefix "bbdb-") | |
325 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/83 | |
326 | (enable-old exact "where-is") | |
327 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/60 | |
328 | (disable exact "todo-add-category") | |
329 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/51 | |
330 | (enable exact "find-tag") | |
331 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/89 | |
332 | (enable prefix "etags-select-") | |
333 | ) ; Close paren on separate line for better VC diffs | |
334 | "Default value of `ido-ubiquitous-command-overrides'. | |
335 | ||
336 | You can restore these using the command `ido-ubiquitous-restore-default-overrides'.") | |
337 | ||
338 | (defconst ido-ubiquitous-default-function-overrides | |
339 | '((disable exact "read-file-name") | |
340 | (disable exact "read-file-name-internal") | |
341 | (disable exact "read-buffer") | |
342 | (disable exact "gnus-emacs-completing-read") | |
343 | (disable exact "gnus-iswitchb-completing-read") | |
344 | (disable exact "grep-read-files") | |
345 | (disable exact "magit-builtin-completing-read") | |
346 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/36 | |
347 | (enable exact "bookmark-completing-read") | |
348 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/4 | |
349 | (enable-old exact "webjump-read-choice") | |
350 | (enable-old exact "webjump-read-url-choice") | |
351 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/9 | |
352 | (disable exact "isearchp-read-unicode-char") | |
353 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/38 | |
354 | (enable exact "read-char-by-name") | |
355 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/39 | |
356 | (disable exact "Info-read-node-name") | |
357 | ;; https://github.com/purcell/emacs.d/issues/182#issuecomment-44212927 | |
358 | (disable exact "tmm-menubar") | |
359 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/58 | |
360 | ;; https://github.com/mooz/js2-mode/issues/181 | |
361 | (enable exact "imenu--completion-buffer") | |
362 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/74 | |
363 | (enable-old exact "auto-insert") | |
364 | ;; https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/116 | |
365 | (enable exact "project--completing-read-strict") | |
366 | ) ; Close paren on separate line for better VC diffs | |
367 | "Default value of `ido-ubiquitous-function-overrides'. | |
368 | ||
369 | You can restore these using the command `ido-ubiquitous-restore-default-overrides'.") | |
370 | ||
371 | (defcustom ido-ubiquitous-command-overrides ido-ubiquitous-default-command-overrides | |
372 | "List of command override specifications for ido-ubiquitous | |
373 | ||
374 | Each override specification describes how ido-ubiquitous should | |
375 | behave one or many commands. A specification has the | |
376 | form `(BEHAVIOR MATCH-TYPE MATCH-TEXT)'. BEHAVIOR is one of the | |
377 | following: | |
378 | ||
379 | * `disable': ido-ubiquitous should not be used at all for the | |
380 | specified commands; | |
381 | * `enable': ido-ubiquitous may be used with the specified | |
382 | commands, without emulating the old-style default selection | |
383 | of `completing-read'; | |
384 | * `enable-old': ido-ubiquitous may be used with the specified | |
385 | commands, and should emulate the old-style default selection | |
386 | of `completing-read'. | |
387 | ||
388 | MATCH-TYPE affects how MATCH-TEXT is interpreted, as follows: | |
389 | ||
390 | * `exact': the specification only affects the one command | |
391 | whose name is MATCH-TEXT; | |
392 | * `prefix': the specification affects any command whose name | |
393 | starts with MATCH-TEXT (This is useful for specifying a | |
394 | certain behavior for an entire package); | |
395 | * `regexp': the specification affects any command whose name | |
396 | matches MATCH-TEXT (with MATCH-TEXT being interpreted as a | |
397 | regular expression) | |
398 | ||
399 | MATCH-TEXT should be a string. | |
400 | ||
401 | Since this variable's has a somewhat complex structure, it is | |
402 | recommended that you set this variable through Customize. | |
403 | ||
404 | Note that this variable only affects *commands*, which are | |
405 | functions marked as interactive. See | |
406 | `ido-ubiquitous-function-overrides' for how to modify the | |
407 | behavior of ido-ubiquitous for arbitrary functions. | |
408 | ||
409 | Note: If multiple overrides match the same commmand, the first | |
410 | one in the list will take precedence. | |
411 | ||
412 | If you need to add a new specification to this list, please also | |
413 | file a bug report at https://github.com/DarwinAwardWinner/ido-ubiquitous/issues" | |
414 | :type '(repeat ido-ubiquitous-command-override-spec) | |
415 | :group 'ido-ubiquitous) | |
416 | ||
417 | (defmacro ido-ubiquitous-with-override (override &rest body) | |
418 | "Eval BODY with specified OVERRIDE in place. | |
419 | ||
420 | The OVERRIDE argument is evaluated normally, so if it is a | |
421 | literal symbol, it must be quoted. | |
422 | ||
423 | See `ido-ubiquitous-command-overrides' for valid override types." | |
424 | (declare (indent 1)) | |
425 | ;; Eval override | |
426 | `(let ((ido-ubiquitous-next-override ,override)) | |
427 | ,@body)) | |
428 | ||
429 | (defun ido-ubiquitous-apply-function-override (func override) | |
430 | "Set the override property on FUNC to OVERRIDE and set up advice to apply the override." | |
431 | (setq func (ido-ubiquitous--as-symbol func) | |
432 | override (ido-ubiquitous--as-symbol override)) | |
433 | (if (memq override '(disable enable enable-old nil)) | |
434 | (progn | |
435 | (put func 'ido-ubiquitous-override override) | |
436 | (when override | |
437 | (let ((docstring | |
438 | (format "Override ido-ubiquitous behavior in %s if its `ido-ubiquitous-override' property is non-nil." func))) | |
439 | (eval | |
440 | `(defadvice ,func (around ido-ubiquitous-override activate) | |
441 | ,docstring | |
442 | (let* ((func ',func) | |
443 | (override (get func 'ido-ubiquitous-override))) | |
444 | (when override | |
445 | (ido-ubiquitous--debug-message | |
446 | "Using override `%s' for function `%s'" | |
447 | override func)) | |
448 | (ido-ubiquitous-with-override override | |
449 | ad-do-it))))))) | |
450 | (display-warning | |
451 | 'ido-ubiquitous | |
452 | (format "Ignoring invalid override action `%s' for function `%s' found in `ido-ubiquitous-function-overrides'." | |
453 | override func) | |
454 | :warning))) | |
455 | ||
456 | (defun ido-ubiquitous-set-function-overrides (sym newval) | |
457 | "Custom setter function for `ido-ubiquitous-function-overrides'. | |
458 | ||
459 | In addition to setting the variable, this also sets up advice on | |
460 | each function to apply the appropriate override." | |
461 | ;; Unset all previous overrides | |
462 | (when (boundp sym) | |
463 | (let ((oldval (eval sym))) | |
464 | (cl-loop for (_action _match-type func) in oldval | |
465 | do (ido-ubiquitous-apply-function-override func nil)))) | |
466 | ;; Ensure that function names are strings, not symbols | |
467 | (setq newval | |
468 | (cl-loop for (action match-type func) in newval | |
469 | collect (list action match-type | |
470 | (ido-ubiquitous--as-string func)))) | |
471 | ;; set new overrides | |
472 | (cl-loop for override in newval | |
473 | for (action match-type func) = override | |
474 | ||
475 | ;; Remove duplicate overrides | |
476 | if (member func overridden-functions) | |
477 | do (display-warning | |
478 | 'ido-ubiquitous | |
479 | (format | |
480 | "Removing duplicate override for function `%s'" func)) | |
481 | ||
482 | ;; Apply valid overrides | |
483 | else if (eq match-type 'exact) | |
484 | do (ido-ubiquitous-apply-function-override func action) | |
485 | and collect func into overridden-functions | |
486 | and collect override into final-value | |
487 | ||
488 | ;; Remove invalid overrides | |
489 | else | |
490 | do (display-warning | |
491 | 'ido-ubiquitous | |
492 | (format | |
493 | "Removing invalid function override match-type `%s' for function `%s'; only match-type `exact' is supported in `ido-ubiquitous-function-overrides'." | |
494 | match-type func)) | |
495 | ||
496 | ;; Set the value to only the overrides that were actually | |
497 | ;; applied. | |
498 | finally return | |
499 | (set-default sym final-value))) | |
500 | ||
501 | (defcustom ido-ubiquitous-auto-update-overrides 'notify | |
502 | "Whether to add new overrides when updating ido-ubiquitous. | |
503 | ||
504 | Ido-ubiquitous comes with a default set of overrides for commands | |
505 | that are known to require them. New versions of ido-ubiquitous | |
506 | may come with updates to the default overrides as more commands | |
507 | are discovered to require them. However, customizing your own | |
508 | overrides would normally prevent you from receiving these | |
509 | updates, since Emacs will not overwrite your customizations. | |
510 | ||
511 | To resolve this problem, you can set this variable to `t', and | |
512 | then ido-ubiquitous can automatically add any new built-in | |
513 | overrides whenever it is updated. (Actually, the update will | |
514 | happen the next time Emacs is restarted after the update.) This | |
515 | allows you to add your own overrides but still receive updates to | |
516 | the default set. The default overrides will always be added with | |
517 | lower precedence than user-added ones. | |
518 | ||
519 | If you want ido-ubiquitous to just notify you about new default | |
520 | overrides instead of adding them itself, set this variable to | |
521 | `notify'. If you don't want this auto-update behavior at all, set | |
522 | it to `nil'. | |
523 | ||
524 | (Note that having this option enabled effectively prevents you | |
525 | from removing any of the built-in default overrides, since they | |
526 | will simply be re-added the next time Emacs starts. However, your | |
527 | custom overrides will still take precedence, so this shouldn't be | |
528 | a problem.)" | |
529 | :type '(choice :tag "When new overrides are available:" | |
530 | (const :menu-tag "Auto-add" | |
531 | :tag "Add them automatically" | |
532 | t) | |
533 | (const :menu-tag "Notify" | |
534 | :tag "Notify the user about them" | |
535 | notify) | |
536 | (const :menu-tag "Ignore" | |
537 | :tag "Ignore them" | |
538 | nil)) | |
539 | :group 'ido-ubiquitous) | |
540 | ||
541 | (defcustom ido-ubiquitous-function-overrides ido-ubiquitous-default-function-overrides | |
542 | "List of function override specifications for ido-ubiquitous | |
543 | ||
544 | Function override specifications have a similar structure to | |
545 | command override specifications (see | |
546 | `ido-ubiquitous-command-overrides'). A function override | |
547 | specification has the form `(BEHAVIOR MATCH-TYPE MATCH-TEXT)'. | |
548 | However, `MATCH-TYPE' may ONLY be `exact'; No other match type is | |
549 | supported. | |
550 | ||
551 | Note: If multiple overrides are set for the same function, the | |
552 | first one in the list will take precedence, and the rest will be | |
553 | ignored and deleted from the override list, with a warning. | |
554 | Invalid override specifications will also be deleted with a | |
555 | warning. | |
556 | ||
557 | If you need to add a new specification to this list, please also file a | |
558 | bug report at https://github.com/DarwinAwardWinner/ido-ubiquitous/issues | |
559 | ||
560 | Setting this variable directly has no effect. You must set it | |
561 | through Customize." | |
562 | :type '(repeat ido-ubiquitous-function-override-spec) | |
563 | :set 'ido-ubiquitous-set-function-overrides | |
564 | :group 'ido-ubiquitous) | |
565 | ||
566 | (defcustom ido-ubiquitous-allow-on-functional-collection nil | |
567 | "Allow ido completion when COLLECTION is a function. | |
568 | ||
569 | The `completing-read' function allows its COLLECTION argument to | |
570 | be a function instead of a list of choices. Some such functions | |
571 | simply return a list of completions and are suitable for use with | |
572 | ido, but others implement more complex behavior and will result | |
573 | in incorrect behavior if used with ido. Since there is no way to | |
574 | tell the difference, this preference defaults to nil, which means | |
575 | that ido-ubiquitous will not work when COLLECTION is a function | |
576 | unless there is a specific override in effect. To disable this | |
577 | safeguard and GUARANTEE ERRORS on some functions, you may set | |
578 | this to non-nil, but this is not recommended." | |
579 | :type 'boolean | |
580 | :group 'ido-ubiquitous) | |
581 | ||
582 | ;;; ido-ubiquitous core | |
583 | ||
584 | ;; These variable are used to make ido-ubiquitous work properly in the | |
585 | ;; case that `completing-read' is called recursively (which is | |
586 | ;; possible when `enable-recursive-minibuffers' is non-nil.) | |
587 | (defvar ido-ubiquitous-enable-next-call nil | |
588 | "If non-nil, then the next call to `ido-completing-read' is by ido-ubiquitous.") | |
589 | (defvar ido-ubiquitous-enable-this-call nil | |
590 | "If non-nil, then the current call to `ido-completing-read' is by ido-ubiquitous.") | |
591 | (defvar ido-ubiquitous-next-override nil | |
592 | "This holds the override to be applied on the next call to `completing-read'. | |
593 | ||
594 | It's value can be nil or one of the symbols `disable', `enable', or | |
595 | `enable-old'. | |
596 | ||
597 | You should not modify this variable directly. Instead use the | |
598 | macro `ido-ubiquitous-with-override'.") | |
599 | (defvar ido-ubiquitous-active-override nil | |
600 | "This holds the override being applied to the current call to `completing-read'. | |
601 | ||
602 | It's value can be nil or one of the symbols `disable', `enable', or | |
603 | `enable-old'. | |
604 | ||
605 | You should not modify this variable directly. Instead use the | |
606 | macro `ido-ubiquitous-with-override'.") | |
607 | (defvar ido-ubiquitous-active-state nil | |
608 | "This holds the ido-ubiquitous mode of operation for the current call to `completing-read'. | |
609 | ||
610 | It's value can be nil or one of the symbols `disable', `enable', or | |
611 | `enable-old'. | |
612 | ||
613 | You should not modify this variable directly.") | |
614 | ||
615 | (defadvice ido-completing-read (around ido-ubiquitous activate) | |
616 | "Enable ido-ubiquitous features if this call was done through ido-ubiquitous. | |
617 | ||
618 | This advice ensures that `ido-ubiquitous-enable-this-call' is set | |
619 | properly while `ido-completing-read' is executing. This variable | |
620 | is used to determine whether to enable certain behaviors only for | |
621 | ido-ubiquitous, not for ordinary ido completion." | |
622 | ;; Set "this" and clear "next" so it doesn't apply to nested calls. | |
623 | (let* ((ido-ubiquitous-enable-this-call ido-ubiquitous-enable-next-call) | |
624 | (ido-ubiquitous-enable-next-call nil) | |
625 | (ido-ubiquitous-initial-item nil)) | |
626 | ad-do-it)) | |
627 | ||
628 | ;; Signal used to trigger fallback (don't use `define-error' because | |
629 | ;; it's only supported in 24.4 and up) | |
630 | (put 'ido-ubiquitous-fallback 'error-conditions '(ido-ubiquitous-fallback error)) | |
631 | (put 'ido-ubiquitous-fallback 'error-message "ido-ubiquitous-fallback") | |
632 | ||
633 | (defun completing-read-ido-ubiquitous | |
634 | (prompt collection &optional predicate | |
635 | require-match initial-input | |
636 | hist def inherit-input-method) | |
637 | "ido-based method for reading from the minibuffer with completion. | |
638 | ||
639 | See `completing-read' for the meaning of the arguments. | |
640 | ||
641 | This function is a wrapper for `ido-completing-read' designed to | |
642 | be used as the value of `completing-read-function'. Importantly, | |
643 | it detects edge cases that ido cannot handle and uses normal | |
644 | completion for them." | |
645 | (let (;; Save the original arguments in case we need to do the | |
646 | ;; fallback | |
647 | (orig-args | |
648 | (list prompt collection predicate require-match | |
649 | initial-input hist def inherit-input-method))) | |
650 | ;; Outer `condition-case' is the fallback handler | |
651 | (condition-case sig | |
652 | ;; Inner `condition-case' converts any unexpected errors into | |
653 | ;; fallback signals. | |
654 | (condition-case err | |
655 | (let* (;; Set the active override and clear the "next" one so it | |
656 | ;; doesn't apply to nested calls. | |
657 | (ido-ubiquitous-active-override ido-ubiquitous-next-override) | |
658 | (ido-ubiquitous-next-override nil) | |
659 | ;; Apply the active override, if any | |
660 | (ido-ubiquitous-active-state | |
661 | (or ido-ubiquitous-active-override | |
662 | ido-ubiquitous-default-state | |
663 | 'enable))) | |
664 | ;; If ido-ubiquitous is disabled this time, fall back | |
665 | (when (eq ido-ubiquitous-active-state 'disable) | |
666 | (signal 'ido-ubiquitous-fallback | |
667 | '("`ido-ubiquitous-active-state' is `disable'"))) | |
668 | ;; Handle a collection that is a function: either expand | |
669 | ;; completion list now or fall back | |
670 | (when (functionp collection) | |
671 | (if (or ido-ubiquitous-allow-on-functional-collection | |
672 | (memq ido-ubiquitous-active-override | |
673 | '(enable enable-old))) | |
674 | (setq collection (all-completions "" collection predicate) | |
675 | ;; `all-completions' will apply the predicate, | |
676 | ;; so it now becomes redundant. | |
677 | predicate nil) | |
678 | (signal 'ido-ubiquitous-fallback | |
679 | '("COLLECTION is a function and there is no override")))) | |
680 | (let ((ido-ubiquitous-enable-next-call t)) | |
681 | (ido-completing-read+ | |
682 | prompt collection predicate require-match | |
683 | initial-input hist def inherit-input-method))) | |
684 | ;; Pass through any known fallback signals to the outer | |
685 | ;; `condition-case' | |
686 | (ido-ubiquitous-fallback | |
687 | (signal (car err) (cdr err))) | |
688 | ;; Convert any other error into a fallback signal. | |
689 | (error | |
690 | (signal 'ido-ubiquitous-fallback | |
691 | (list (format "ido-ubiquitous encountered an unexpected error: %S" | |
692 | err))))) | |
693 | ;; Handler for ido-ubiquitous-fallback signal | |
694 | (ido-ubiquitous-fallback | |
695 | (ido-ubiquitous--explain-fallback sig) | |
696 | (apply ido-cr+-fallback-function orig-args))))) | |
697 | (define-obsolete-function-alias 'completing-read-ido 'completing-read-ido-ubiquitous | |
698 | "ido-ubiquitous 3.0") | |
699 | ||
700 | ;;; Old-style default support | |
701 | ||
702 | (defvar ido-ubiquitous-initial-item nil | |
703 | "The first item selected when ido starts. | |
704 | ||
705 | This is initialized to the first item in the list of completions | |
706 | when ido starts, and is cleared when any character is entered | |
707 | into the prompt or the list is cycled. If it is non-nil and still | |
708 | equal to the first item in the completion list when ido exits, | |
709 | then if `ido-ubiquitous-active-state' is `enable-old', ido | |
710 | returns an empty string instead of the first item on the list.") | |
711 | ||
712 | (defmacro ido-ubiquitous-set-initial-item (item) | |
713 | "Wrapper for `(setq ido-ubiquitous-initial-item ITEM)'. | |
714 | ||
715 | This wrapper differs from simply doing `(setq | |
716 | ido-ubiquitous-initial-item ITEM)' in several ways. First, it has | |
717 | no effect (and does not evaluate ITEM) unless | |
718 | `ido-ubiquitous-active-state' is `enable-old'. Second, it emits | |
719 | appropriate debug messages." | |
720 | `(when (eq ido-ubiquitous-active-state 'enable-old) | |
721 | (let ((item ,item)) | |
722 | (cond | |
723 | (item | |
724 | (ido-ubiquitous--debug-message | |
725 | "Setting `ido-ubiquitous-initial-item' to `%S'." | |
726 | item)) | |
727 | (ido-ubiquitous-initial-item | |
728 | (ido-ubiquitous--debug-message "Clearing `ido-ubiquitous-initial-item'."))) | |
729 | (setq ido-ubiquitous-initial-item item)))) | |
730 | ||
731 | (defadvice ido-read-internal (before ido-ubiquitous-clear-initial-item activate) | |
732 | (ido-ubiquitous-set-initial-item nil)) | |
733 | ||
734 | (defadvice ido-make-choice-list (after ido-ubiquitous-set-initial-item activate) | |
735 | (ido-ubiquitous-set-initial-item | |
736 | (when (and ad-return-value (listp ad-return-value)) | |
737 | (car ad-return-value)))) | |
738 | ||
739 | (defadvice ido-next-match (after ido-ubiquitous-clear-initial-item activate) | |
740 | (ido-ubiquitous-set-initial-item nil)) | |
741 | ||
742 | (defadvice ido-prev-match (after ido-ubiquitous-clear-initial-item activate) | |
743 | (ido-ubiquitous-set-initial-item nil)) | |
744 | ||
745 | ;; Clear initial item after `self-insert-command' | |
746 | (defun ido-ubiquitous-post-insert-hook () | |
747 | (eval '(ido-ubiquitous-set-initial-item nil))) | |
748 | ||
749 | (defun ido-ubiquitous-ido-minibuffer-setup-hook () | |
750 | (add-hook | |
751 | 'post-self-insert-hook | |
752 | #'ido-ubiquitous-post-insert-hook | |
753 | nil | |
754 | 'local)) | |
755 | ||
756 | (add-hook 'ido-minibuffer-setup-hook | |
757 | #'ido-ubiquitous-ido-minibuffer-setup-hook) | |
758 | ||
759 | (defun ido-ubiquitous-should-use-old-style-default () | |
760 | "Returns non nil if ido-ubiquitous should emulate old-style default. | |
761 | ||
762 | This function simply encapsulates all the checks that need to be | |
763 | done in order to decide whether to swap RET and C-j. See | |
764 | `ido-ubiquitous-default-state' for more information." | |
765 | ;; These checks outside the loop don't produce debug messages | |
766 | (and | |
767 | ;; Only if old-style default enabled | |
768 | (eq ido-ubiquitous-active-state 'enable-old) | |
769 | ;; This loop is just an implementation of `and' that reports which | |
770 | ;; arg was nil for debugging purposes. | |
771 | (cl-loop | |
772 | for test in | |
773 | '((bound-and-true-p ido-cur-item) | |
774 | ;; Only if completing a list, not a buffer or file | |
775 | (eq ido-cur-item 'list) | |
776 | ;; Only if this call was done through ido-ubiquitous | |
777 | ido-ubiquitous-enable-this-call | |
778 | ;; Only if default is nil | |
779 | (null ido-default-item) | |
780 | ;; Only if input is empty | |
781 | (string= ido-text "") | |
782 | ;; Only if `ido-ubiquitous-initial-item' hasn't been cleared | |
783 | ido-ubiquitous-initial-item | |
784 | ;; Only if initial item hasn't changed | |
785 | (string= (car ido-cur-list) | |
786 | ido-ubiquitous-initial-item)) | |
787 | for test-result = (eval test) | |
788 | if (not test-result) | |
789 | do (ido-ubiquitous--debug-message | |
790 | "Not enabling old-style default selection because `%S' is nil" | |
791 | test) | |
792 | and return nil | |
793 | finally do (ido-ubiquitous--debug-message | |
794 | "Enabling old-style default selection") | |
795 | finally return t))) | |
796 | ||
797 | (defadvice ido-exit-minibuffer (around ido-ubiquitous-old-style-default-compat activate) | |
798 | "Emulate a quirk of `completing-read'. | |
799 | ||
800 | > If the input is null, `completing-read' returns DEF, or the | |
801 | > first element of the list of default values, or an empty string | |
802 | > if DEF is nil, regardless of the value of REQUIRE-MATCH. | |
803 | ||
804 | See `ido-ubiquitous-default-state', which controls whether this | |
805 | advice has any effect." | |
806 | (condition-case nil | |
807 | (if (ido-ubiquitous-should-use-old-style-default) | |
808 | (let ((ido-ubiquitous-active-state 'enable)) | |
809 | (ido-select-text)) | |
810 | ad-do-it) | |
811 | (error | |
812 | (display-warning 'ido-ubiquitous "Advice on `ido-exit-minibuffer' failed." :warning) | |
813 | ad-do-it)) | |
814 | (ido-ubiquitous-set-initial-item nil)) | |
815 | ||
816 | (defadvice ido-select-text (around ido-ubiquitous-old-style-default-compat activate) | |
817 | "Emulate a quirk of `completing-read'. | |
818 | ||
819 | > If the input is null, `completing-read' returns DEF, or the | |
820 | > first element of the list of default values, or an empty string | |
821 | > if DEF is nil, regardless of the value of REQUIRE-MATCH. | |
822 | ||
823 | See `ido-ubiquitous-default-state', which controls whether this | |
824 | advice has any effect." | |
825 | (condition-case nil | |
826 | (if (ido-ubiquitous-should-use-old-style-default) | |
827 | (let ((ido-ubiquitous-active-state 'enable)) | |
828 | (ido-exit-minibuffer)) | |
829 | ad-do-it) | |
830 | (error | |
831 | (display-warning 'ido-ubiquitous "Advice on `ido-select-text' failed." :warning) | |
832 | ad-do-it)) | |
833 | (ido-ubiquitous-set-initial-item nil)) | |
834 | ||
835 | ;;; Overrides | |
836 | ||
837 | (defun ido-ubiquitous--overrides-have-same-target-p (o1 o2) | |
838 | (cl-destructuring-bind (oride1 type1 text1) o1 | |
839 | (cl-destructuring-bind(oride2 type2 text2) o2 | |
840 | ;; Avoid warnings about unused vars | |
841 | oride1 oride2 | |
842 | (and (string= text1 text2) | |
843 | (eq type1 type2))))) | |
844 | ||
845 | (defun ido-ubiquitous--combine-override-lists (olist1 olist2) | |
846 | "Append OLIST2 to OLIST1, but remove redundant elements. | |
847 | ||
848 | Redundancy is determined using | |
849 | `ido-ubiquitous--overrides-have-same-target-p'." | |
850 | (let ((olist2 | |
851 | (cl-remove-if | |
852 | (lambda (o2) (cl-member | |
853 | o2 olist1 | |
854 | :test #'ido-ubiquitous--overrides-have-same-target-p)) | |
855 | olist2))) | |
856 | (append olist1 olist2))) | |
857 | ||
858 | (defun ido-ubiquitous-update-overrides (&optional save quiet) | |
859 | "Re-add the default overrides without erasing custom overrides. | |
860 | ||
861 | This is useful after an update of ido-ubiquitous that adds new | |
862 | default overrides. See `ido-ubiquitous-auto-update-overrides' for | |
863 | more information. | |
864 | ||
865 | If SAVE is non-nil, also save the overrides to the user's custom | |
866 | file (but only if they were already customized). When called | |
867 | interactively, a prefix argument triggers a save. | |
868 | ||
869 | When called from Lisp code, this function returns the list of | |
870 | variables whose values were modified. In particular, it returns | |
871 | non-nil if any variables were modified, and nil if no modifications | |
872 | were made." | |
873 | (interactive "P") | |
874 | (let ((unmodified-vars nil) | |
875 | (updated-vars nil) | |
876 | (final-message-lines nil) | |
877 | (final-message-is-warning nil)) | |
878 | (cl-loop | |
879 | for (var def) in | |
880 | '((ido-ubiquitous-command-overrides | |
881 | ido-ubiquitous-default-command-overrides) | |
882 | (ido-ubiquitous-function-overrides | |
883 | ido-ubiquitous-default-function-overrides)) | |
884 | do (let* ((var-state (custom-variable-state var (eval var))) | |
885 | (curval (eval var)) | |
886 | (defval (eval def)) | |
887 | (newval (ido-ubiquitous--combine-override-lists | |
888 | curval defval))) | |
889 | (cond | |
890 | ;; Nothing to add to var, do nothing | |
891 | ((and (equal curval newval) | |
892 | (eq var-state 'saved)) | |
893 | (ido-ubiquitous--debug-message | |
894 | "No need to modify value of option `%s'" | |
895 | var) | |
896 | (push var unmodified-vars)) | |
897 | ;; Var is not customized, just set the new default | |
898 | ((eq var-state 'standard) | |
899 | (ido-ubiquitous--debug-message | |
900 | "Setting uncustomized option `%s' to its default value" | |
901 | var) | |
902 | (push var unmodified-vars) | |
903 | (set var defval)) | |
904 | ;; Var is saved to custom.el, set and save new value (if | |
905 | ;; SAVE is t) | |
906 | ((and save | |
907 | (eq var-state 'saved)) | |
908 | (ido-ubiquitous--debug-message | |
909 | "Updating option `%s' with new overrides and saving it." | |
910 | var) | |
911 | (push var updated-vars) | |
912 | (customize-save-variable var newval)) | |
913 | ;; Var is modified but not saved (or SAVE is nil), update it | |
914 | ;; but don't save it | |
915 | (t | |
916 | (ido-ubiquitous--debug-message | |
917 | "Updating option `%s' with new overrides but not saving it for future sessions." | |
918 | var) | |
919 | (push var updated-vars) | |
920 | (customize-set-variable var newval))))) | |
921 | (unless quiet | |
922 | ;; Now compose a single message that summarizes what was done | |
923 | (if (null updated-vars) | |
924 | (push "No updates to ido-ubiquitous override variables were needed." | |
925 | final-message-lines) | |
926 | (push | |
927 | (format "Updated the following ido-ubiquitous override variables: %S" | |
928 | (sort updated-vars #'string<)) | |
929 | final-message-lines) | |
930 | (if save | |
931 | (push | |
932 | "All updated variables were successfully saved." | |
933 | final-message-lines) | |
934 | (push | |
935 | "However, they have not been saved for future sessions. To save them, re-run this command with a prefix argument: `C-u M-x ido-ubiquitous-update-overrides'; or else manually inspect and save their values using `M-x customize-group ido-ubiquitous'." | |
936 | final-message-lines) | |
937 | (setq final-message-is-warning t))) | |
938 | (if final-message-is-warning | |
939 | (display-warning 'ido-ubiquitous | |
940 | (mapconcat 'identity (nreverse final-message-lines) "\n")) | |
941 | (message (mapconcat 'identity (nreverse final-message-lines) "\n")))) | |
942 | updated-vars)) | |
943 | ||
944 | (defun ido-ubiquitous--find-override-updates (current-value available-updates) | |
945 | (cl-set-difference (ido-ubiquitous--combine-override-lists | |
946 | current-value available-updates) | |
947 | current-value)) | |
948 | ||
949 | (defun ido-ubiquitous--maybe-update-overrides () | |
950 | "Maybe call `ido-ubiquitous-update-overrides. | |
951 | ||
952 | See `ido-ubiquitous-auto-update-overrides." | |
953 | (if ido-ubiquitous-auto-update-overrides | |
954 | (let* ((command-override-updates | |
955 | (ido-ubiquitous--find-override-updates | |
956 | ido-ubiquitous-command-overrides | |
957 | ido-ubiquitous-default-command-overrides)) | |
958 | (function-override-updates | |
959 | (ido-ubiquitous--find-override-updates | |
960 | ido-ubiquitous-function-overrides | |
961 | ido-ubiquitous-default-function-overrides)) | |
962 | (update-count | |
963 | (+ (length command-override-updates) | |
964 | (length function-override-updates)))) | |
965 | (if (> update-count 0) | |
966 | (if (eq ido-ubiquitous-auto-update-overrides 'notify) | |
967 | (display-warning | |
968 | 'ido-ubiquitous | |
969 | (format "There are %s new overrides available. Use `M-x ido-ubiquitous-update-overrides' to enable them. (See `ido-ubiquitous-auto-update-overrides' for more information.)" | |
970 | update-count)) | |
971 | (ido-ubiquitous--debug-message "Applying override updates.") | |
972 | (ido-ubiquitous-update-overrides t)) | |
973 | (ido-ubiquitous--debug-message "No override updates availble."))) | |
974 | (ido-ubiquitous--debug-message "Skipping override updates by user preference."))) | |
975 | ||
976 | (define-obsolete-function-alias | |
977 | 'ido-ubiquitous-restore-default-overrides | |
978 | 'ido-ubiquitous-update-overrides | |
979 | "ido-ubiquitous 3.9") | |
980 | ||
981 | (defun ido-ubiquitous-spec-match (spec symbol) | |
982 | "Returns t if SPEC matches SYMBOL (which should be a function name). | |
983 | ||
984 | See `ido-ubiquitous-command-overrides'. If the match spec is | |
985 | invalid or any other error occurs, the error is demoted to a | |
986 | warning and the function returns nil." | |
987 | (condition-case err | |
988 | (when (and symbol (symbolp symbol)) | |
989 | (cl-destructuring-bind (type text) spec | |
990 | (let ((matcher (cdr (assoc type ido-ubiquitous-spec-matchers))) | |
991 | (text (ido-ubiquitous--as-string text)) | |
992 | (symname (ido-ubiquitous--as-string symbol))) | |
993 | (if matcher | |
994 | (funcall matcher text symname) | |
995 | ;; If the matcher is invalid, issue a warning and return | |
996 | ;; nil. | |
997 | (error "Unknown match spec type \"%s\". See `ido-ubiquitous-spec-matchers' for valid types." type) | |
998 | nil)))) | |
999 | (error | |
1000 | (display-warning 'ido-ubiquitous "Error during ido-ubiquitous spec matching: %S" err) | |
1001 | nil))) | |
1002 | ||
1003 | (defun ido-ubiquitous-get-command-override (cmd) | |
1004 | "Return the override associated with the command CMD. | |
1005 | ||
1006 | If there is no override set for CMD in | |
1007 | `ido-ubiquitous-command-overrides', return nil." | |
1008 | (when (and cmd (symbolp cmd)) | |
1009 | (cl-loop for override in ido-ubiquitous-command-overrides | |
1010 | for (action . spec) = override | |
1011 | for valid-action = (and (memq action '(disable enable enable-old nil)) | |
1012 | (assoc (car spec) ido-ubiquitous-spec-matchers)) | |
1013 | unless valid-action | |
1014 | do (progn | |
1015 | (display-warning | |
1016 | 'ido-ubiquitous | |
1017 | (format "Removing invalid override `%S' from `ido-ubiquitous-command-overrides'" | |
1018 | (cons action spec)) | |
1019 | :warning) | |
1020 | (setq ido-ubiquitous-command-overrides | |
1021 | (remove override ido-ubiquitous-command-overrides))) | |
1022 | when (and valid-action (ido-ubiquitous-spec-match spec cmd)) | |
1023 | return action | |
1024 | ||
1025 | finally return nil))) | |
1026 | ||
1027 | ;;; Workaround for https://github.com/DarwinAwardWinner/ido-ubiquitous/issues/24 | |
1028 | ||
1029 | ;; When `call-interactively' is advised, `called-interactively-p' | |
1030 | ;; always returns nil. So we redefine it (and `interactive-p') to test | |
1031 | ;; the correct condition. | |
1032 | ||
1033 | (defsubst ido-ubiquitous--looks-like-advised-orig (func) | |
1034 | "Returns t if FUNC is a symbol starting with \"ad-Orig-\". | |
1035 | ||
1036 | Such symbols are used to store the original definitions of | |
1037 | functions that have been advised by `defadvice' or similar." | |
1038 | (and (symbolp func) | |
1039 | (string-prefix-p "ad-Orig-" (symbol-name func)))) | |
1040 | ||
1041 | (defsubst ido-ubiquitous--looks-like-call-interactively (func) | |
1042 | "Returns t if FUNC looks like the function `call-interactively'. | |
1043 | ||
1044 | FUNC \"looks like\" `call-interactively' if it is the literal | |
1045 | symbol `call-interactively', or the value of `(symbol-function | |
1046 | 'call-interactively)', or a symbol whose `symbol-function' is the | |
1047 | same as that of `call-interactively'. | |
1048 | ||
1049 | This function is used to determine whether a given function was | |
1050 | \"called by\" `call-interactively' and therefore was called | |
1051 | interactively." | |
1052 | (when func | |
1053 | (eq (symbol-function 'call-interactively) | |
1054 | (if (symbolp func) | |
1055 | (symbol-function func) | |
1056 | func)))) | |
1057 | ||
1058 | (defun ido-ubiquitous--backtrace-from (fun) | |
1059 | "Return all backtrace frames, starting with the one for FUN. | |
1060 | ||
1061 | FUN may be a list of functions, in which case the first one found | |
1062 | on the stack will be used." | |
1063 | (let ((stack | |
1064 | (cl-loop for i upfrom 0 | |
1065 | for frame = (backtrace-frame i) | |
1066 | while frame | |
1067 | collect frame)) | |
1068 | (funcs (if (functionp fun) | |
1069 | (list fun) | |
1070 | fun))) | |
1071 | (while (and stack | |
1072 | (not (memq (cl-cadar stack) funcs))) | |
1073 | (setq stack (cdr stack))) | |
1074 | stack)) | |
1075 | ||
1076 | (defun ido-ubiquitous--clean-advice-from-backtrace (stack) | |
1077 | "Takes a stack trace and cleans all evidence of advice. | |
1078 | ||
1079 | Specifically, for each call to a function starting with | |
1080 | \"ad-Orig-\", that call and all prior calls up to but not | |
1081 | including the advised function's original name are deleted from | |
1082 | the stack." | |
1083 | (let ((skipping-until nil)) | |
1084 | (cl-loop for frame in stack | |
1085 | for func = (cadr frame) | |
1086 | ;; Check if we found the frame we we're skipping to | |
1087 | if (and skipping-until | |
1088 | (eq func skipping-until)) | |
1089 | do (setq skipping-until nil) | |
1090 | ;; If we're looking at an the original form of an advised | |
1091 | ;; function, skip until the real name of that function. | |
1092 | if (and (not skipping-until) | |
1093 | (ido-ubiquitous--looks-like-advised-orig func)) | |
1094 | do (setq skipping-until | |
1095 | (intern | |
1096 | (substring (symbol-name func) | |
1097 | (eval-when-compile (length "ad-Orig-"))))) | |
1098 | unless skipping-until collect frame))) | |
1099 | ||
1100 | (defsubst ido-ubiquitous--interactive-internal () | |
1101 | "Equivalent of the INTERACTIVE macro in the Emacs C source. | |
1102 | ||
1103 | This is an internal function that should never be called | |
1104 | directly. | |
1105 | ||
1106 | See the C source for the logic behind this function." | |
1107 | (and (not executing-kbd-macro) | |
1108 | (not noninteractive))) | |
1109 | ||
1110 | (defun ido-ubiquitous--interactive-p-internal () | |
1111 | "Equivalent of C function \"interactive_p\". | |
1112 | ||
1113 | This is an internal function that should never be called | |
1114 | directly. | |
1115 | ||
1116 | See the C source for the logic behind this function." | |
1117 | (let ((stack | |
1118 | ;; We clean advice from the backtrace. This ensures that we | |
1119 | ;; get the right answer even if `call-interactively' has been | |
1120 | ;; advised. | |
1121 | (ido-ubiquitous--clean-advice-from-backtrace | |
1122 | (cdr | |
1123 | (ido-ubiquitous--backtrace-from | |
1124 | '(called-interactively-p interactive-p)))))) | |
1125 | ;; See comments in the C function for the logic here. | |
1126 | (while (and stack | |
1127 | (or (eq (cl-cadar stack) 'bytecode) | |
1128 | (null (caar stack)))) | |
1129 | (setq stack (cdr stack))) | |
1130 | ;; Top of stack is now the function that we want to know | |
1131 | ;; about. Pop it, then check if the next function is | |
1132 | ;; `call-interactively', using a more permissive test than the default. | |
1133 | (ido-ubiquitous--looks-like-call-interactively (cl-cadadr stack)))) | |
1134 | ||
1135 | (defadvice call-interactively (around ido-ubiquitous activate) | |
1136 | "Implements the behavior specified in `ido-ubiquitous-command-overrides'." | |
1137 | (let* ((cmd (ad-get-arg 0)) | |
1138 | (override (ido-ubiquitous-get-command-override cmd))) | |
1139 | (when override | |
1140 | (ido-ubiquitous--debug-message "Using override `%s' for command `%s'" | |
1141 | override cmd)) | |
1142 | (ido-ubiquitous-with-override override | |
1143 | ad-do-it))) | |
1144 | ||
1145 | ;; Work around `called-interactively-p' in Emacs 24.3 and earlier, | |
1146 | ;; which always returns nil when `call-interactively' is advised. | |
1147 | (when (not (and (featurep 'nadvice) | |
1148 | (boundp 'called-interactively-p-functions))) | |
1149 | ||
1150 | (defadvice interactive-p (around ido-ubiquitous activate) | |
1151 | "Return the correct result when `call-interactively' is advised. | |
1152 | ||
1153 | This advice completely overrides the original definition." | |
1154 | (condition-case nil | |
1155 | (setq ad-return-value | |
1156 | (and (ido-ubiquitous--interactive-internal) | |
1157 | (ido-ubiquitous--interactive-p-internal))) | |
1158 | ;; In case of error in the advice, fall back to the default | |
1159 | ;; implementation | |
1160 | (error ad-do-it))) | |
1161 | ||
1162 | (defadvice called-interactively-p (around ido-ubiquitous activate) | |
1163 | "Return the correct result when `call-interactively' is advised. | |
1164 | ||
1165 | This advice completely overrides the original definition." | |
1166 | (condition-case nil | |
1167 | (setq ad-return-value | |
1168 | (and (or (ido-ubiquitous--interactive-internal) | |
1169 | (not (eq kind 'interactive))) | |
1170 | (ido-ubiquitous--interactive-p-internal))) | |
1171 | ;; In case of error in the advice, fall back to the default | |
1172 | ;; implementation | |
1173 | (error ad-do-it)))) | |
1174 | ||
1175 | ;;; Other | |
1176 | ||
1177 | (defsubst ido-ubiquitous--fixup-old-advice () | |
1178 | ;; Clean up old versions of ido-ubiquitous advice if they exist | |
1179 | (ignore-errors (ad-remove-advice 'completing-read 'around 'ido-ubiquitous)) | |
1180 | (ignore-errors (ad-remove-advice 'ido-completing-read 'around 'detect-replacing-cr)) | |
1181 | (ignore-errors (ad-remove-advice 'ido-magic-forward-char 'before 'ido-ubiquitous-fallback)) | |
1182 | (ignore-errors (ad-remove-advice 'ido-magic-backward-char 'before 'ido-ubiquitous-fallback)) | |
1183 | (ignore-errors (ad-remove-advice 'ido-exit-minibuffer 'around 'compatibility)) | |
1184 | (ad-activate-all)) | |
1185 | ||
1186 | (defsubst ido-ubiquitous--fixup-old-magit-overrides () | |
1187 | (let ((old-override '(disable prefix "magit-")) | |
1188 | (new-override '(disable exact "magit-builtin-completing-read"))) | |
1189 | (when (member old-override | |
1190 | ido-ubiquitous-command-overrides) | |
1191 | (customize-set-variable | |
1192 | 'ido-ubiquitous-command-overrides | |
1193 | (remove old-override ido-ubiquitous-command-overrides)) | |
1194 | (unless (member new-override ido-ubiquitous-function-overrides) | |
1195 | (customize-set-variable 'ido-ubiquitous-function-overrides | |
1196 | (append ido-ubiquitous-function-overrides | |
1197 | (list new-override)))) | |
1198 | (display-warning | |
1199 | 'ido-ubiquitous | |
1200 | "Fixing obsolete magit overrides. | |
1201 | ||
1202 | Magit has changed recently such that the old override that | |
1203 | ido-ubiquitous defined for it now causes problems. This old | |
1204 | override has been automatically removed and the new one added. | |
1205 | Please use `M-x customize-group ido-ubiquitous' and review the | |
1206 | override variables and save them to your customization file." | |
1207 | :warning)))) | |
1208 | ||
1209 | (defun ido-ubiquitous-initialize () | |
1210 | "Do initial setup for ido-ubiquitous. | |
1211 | ||
1212 | This only needs to be called once when the file is first loaded. | |
1213 | It cleans up any traces of old versions of ido-ubiquitous and | |
1214 | then sets up the mode." | |
1215 | (ido-ubiquitous--fixup-old-advice) | |
1216 | (ido-ubiquitous--fixup-old-magit-overrides) | |
1217 | (ido-ubiquitous--maybe-update-overrides) | |
1218 | ;; Make sure the mode is turned on/off as specified by the value of | |
1219 | ;; the mode variable | |
1220 | (ido-ubiquitous-mode (if ido-ubiquitous-mode 1 0))) | |
1221 | (ido-ubiquitous-initialize) | |
62 | 'ido-ubiquitous-default-state | |
63 | "For the new variables to control which commands have ido completion, see `ido-cr+-function-blacklist' and `ido-cr+-function-whitelist'. For information on what happened to \"old-style\" default selection, See the FAQ." | |
64 | "ido-completing-read+ 4.0") | |
65 | (make-obsolete-variable | |
66 | 'ido-ubiquitous-command-overrides | |
67 | "For the new variables to control which commands have ido completion, see `ido-cr+-function-blacklist' and `ido-cr+-function-whitelist'. For information on what happened to \"old-style\" default selection, See the FAQ." | |
68 | "ido-completing-read+ 4.0") | |
69 | (make-obsolete-variable | |
70 | 'ido-ubiquitous-function-overrides | |
71 | "For the new variables to control which commands have ido completion, see `ido-cr+-function-blacklist' and `ido-cr+-function-whitelist'. For information on what happened to \"old-style\" default selection, See the FAQ." | |
72 | "ido-completing-read+ 4.0") | |
73 | (make-obsolete-variable | |
74 | 'ido-ubiquitous-allow-on-functional-collection | |
75 | "Ido-cr+ now works with most dynamic completion tables (i.e. \"functional collections\"), so this variable is no longer necessary. If a specific command uses a dynamic completion table that conflicts with ido-cr+, add it to `ido-cr+-function-blacklist' instead." | |
76 | "ido-completing-read+ 4.0") | |
1222 | 77 | |
1223 | 78 | (provide 'ido-ubiquitous) |
79 | ||
1224 | 80 | ;; Local Variables: |
1225 | 81 | ;; indent-tabs-mode: nil |
1226 | 82 | ;; End: |
5 | 5 | perl -i'orig_*' -lape "s/Version: [0-9.]+/Version: $TARGET_VERSION/g;" \ |
6 | 6 | -e "s/((?:defconst|defvar|setq).*-version\s+)\"[0-9.]+\"/\${1}\"$TARGET_VERSION\"/g;" \ |
7 | 7 | -e "s/(Package-Requires.*\(ido-completing-read\+\s+)\"[0-9.]+\"\)/\${1}\"${TARGET_VERSION}\")/g;" \ |
8 | *.el | |
8 | -e "s/\(package \"ido-ubiquitous\" \"[0-9.]+\"/(package \"ido-ubiquitous\" \"${TARGET_VERSION}\"/g" \ | |
9 | *.el Cask | |
9 | 10 | else |
10 | 11 | echo "Usage: $0 VERSION_NUMBER" |
11 | 12 | fi |
0 | ;;; ido-ubiquitous-test.el --- -*- lexical-binding: t -*- | |
1 | ||
2 | ;; Copyright (C) 2015 Ryan C. Thompson | |
3 | ||
4 | ;; Filename: ido-ubiquitous-test.el | |
5 | ;; Author: Ryan C. Thompson | |
6 | ;; Created: Tue Oct 6 20:52:45 2015 (-0700) | |
7 | ||
8 | ;; This file is NOT part of GNU Emacs. | |
9 | ||
10 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
11 | ;; | |
12 | ;; This program is free software: you can redistribute it and/or modify | |
13 | ;; it under the terms of the GNU General Public License as published by | |
14 | ;; the Free Software Foundation, either version 3 of the License, or (at | |
15 | ;; your option) any later version. | |
16 | ;; | |
17 | ;; This program is distributed in the hope that it will be useful, but | |
18 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | ;; General Public License for more details. | |
21 | ;; | |
22 | ;; You should have received a copy of the GNU General Public License | |
23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
24 | ;; | |
25 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
26 | ;; | |
27 | ;;; Code: | |
28 | ||
29 | (require 'ido-completing-read+) | |
30 | (require 'ido-ubiquitous) | |
31 | (require 'ert) | |
32 | (require 'cl-lib) | |
33 | ||
34 | ;; This is a series of macros to facilitate the testing of completion | |
35 | ;; non-interactively by simulating input. | |
36 | ||
37 | (defmacro keyboard-quit-to-error (&rest body) | |
38 | "Evaluate BODY but signal an error on `keyboard-quit'." | |
39 | `(condition-case nil | |
40 | (progn ,@body) | |
41 | (quit | |
42 | (error "Caught `keyboard-quit'")))) | |
43 | ||
44 | (defmacro with-simulated-input (keys &rest body) | |
45 | "Eval body with KEYS as simulated input. | |
46 | ||
47 | This macro is intended for testing normally interactive functions | |
48 | by simulating input. If BODY tries to read more input events than | |
49 | KEYS provides, `keyboard-quit' is invoked (by means of appending | |
50 | multple C-g keys to KEYS). This is to ensure that BODY will never | |
51 | block waiting for input, since this macro is intended for | |
52 | noninteractive use. As such, BODY should not invoke | |
53 | `keyboard-quit' under normal operation, and KEYS should not | |
54 | include C-g, or this macro will interpret it as reading past the | |
55 | end of input." | |
56 | ;; It would be better to detect end-of-input by overriding | |
57 | ;; `read-event' to throw an error, since theoretically C-g could be | |
58 | ;; rebound to something other than `keyboard-quit'. But apparently | |
59 | ;; some functions read input directly in C code, and redefining | |
60 | ;; `read-event' has no effect on those. So the suboptimal solution | |
61 | ;; is to rely on C-g. | |
62 | (declare (indent 1)) | |
63 | `(let* ((key-sequence (listify-key-sequence (kbd ,keys))) | |
64 | (C-g-key-sequence | |
65 | (listify-key-sequence | |
66 | ;; We *really* want to trigger `keyboard-quit' if we reach | |
67 | ;; the end of the input. | |
68 | (kbd "C-g C-g C-g C-g C-g C-g C-g"))) | |
69 | (unread-command-events | |
70 | (append key-sequence C-g-key-sequence))) | |
71 | (when (member (car C-g-key-sequence) key-sequence) | |
72 | (error "KEYS must not include C-g")) | |
73 | (condition-case nil | |
74 | (progn ,@body) | |
75 | (quit | |
76 | (error "Reached end of simulated input while evaluating body"))))) | |
77 | ||
78 | (defmacro with-mode (mode arg &rest body) | |
79 | "Eval (MODE ARG), then body, then restore previous status of MODE. | |
80 | ||
81 | This will only work on modes that respect the normal conventions | |
82 | for activation and deactivation." | |
83 | (declare (indent 2)) | |
84 | `(let* ((orig-status ,mode) | |
85 | (restore-arg (if orig-status 1 0))) | |
86 | (unwind-protect | |
87 | (progn | |
88 | (,mode ,arg) | |
89 | ,@body) | |
90 | (message "Restoring mode %s to %s" ',mode restore-arg) | |
91 | (,mode restore-arg)))) | |
92 | ||
93 | (defmacro with-ido-ubiquitous-standard-env (&rest body) | |
94 | "Execute BODY with standard ido-ubiquitous settings.\n\nAll ido-ubiquitous and ido-cr+ options will be let-bound to their\ndefault values, and `ido-ubiquitous-mode' will be enabled." | |
95 | (declare (indent 0)) | |
96 | (let* | |
97 | ((ido-ubiquitous-options | |
98 | '(ido-ubiquitous-allow-on-functional-collection | |
99 | ido-ubiquitous-command-overrides | |
100 | ido-ubiquitous-debug-mode | |
101 | ido-ubiquitous-default-state | |
102 | ido-ubiquitous-function-overrides | |
103 | ido-cr+-fallback-function | |
104 | ido-cr+-max-items | |
105 | ido-cr+-replace-completely | |
106 | ido-confirm-unique-completion)) | |
107 | (idu-bindings | |
108 | (cl-loop for var in ido-ubiquitous-options collect | |
109 | (list var | |
110 | (list 'quote | |
111 | (eval (car (get var 'standard-value)))))))) | |
112 | `(with-mode ido-ubiquitous-mode 1 | |
113 | (let ,idu-bindings ,@body)))) | |
114 | ||
115 | (defmacro collection-as-function (collection) | |
116 | "Return a function equivalent to COLLECTION. | |
117 | ||
118 | The returned function will work equivalently to COLLECTION when | |
119 | passed to `all-completions' and `try-completion'." | |
120 | `(completion-table-dynamic (lambda (string) (all-completions string ,collection)))) | |
121 | ||
122 | (cl-defmacro should-with-tag (form &key tag) | |
123 | "Equivalent to `(should FORM)' but with a TAG on the output. | |
124 | ||
125 | This is useful if the same `should' form will be called multiple | |
126 | times in different contexts. Each test can pass a different tag | |
127 | so it's clear in the ERT output which context is causing the | |
128 | failure. | |
129 | ||
130 | Note that although this is a macro, the TAG argument is evaluated normally." | |
131 | `(let ((tagvalue ,tag)) | |
132 | (condition-case err | |
133 | (should ,form) | |
134 | (ert-test-failed | |
135 | (message "Error symbol: %S" (car err)) | |
136 | (message "Error data: %S" (cdr err)) | |
137 | (when tagvalue | |
138 | (setf (cadr err) (append (cadr err) (list :tag tagvalue)))) | |
139 | (message "New error data: %S" (cdr err)) | |
140 | (signal (car err) (cdr err)))))) | |
141 | ||
142 | (defun plist-delete (plist property) | |
143 | "Delete PROPERTY from PLIST. | |
144 | This is in contrast to merely setting it to 0." | |
145 | (let (p) | |
146 | (while plist | |
147 | (if (not (eq property (car plist))) | |
148 | (setq p (plist-put p (car plist) (nth 1 plist)))) | |
149 | (setq plist (cddr plist))) | |
150 | p)) | |
151 | ||
152 | (cl-defmacro should-error-with-tag (form &rest other-keys &key tag &allow-other-keys) | |
153 | "Equivalent to `(should FORM)' but with a TAG on the output. | |
154 | See `should-with-tag'. | |
155 | ||
156 | Note that although this is a macro, the TAG argument is evaluated normally." | |
157 | (setq other-keys (plist-delete other-keys :tag)) | |
158 | `(let ((tagvalue ,tag)) | |
159 | (condition-case err | |
160 | (should-error ,form ,@other-keys) | |
161 | (ert-test-failed | |
162 | (message "Error symbol: %S" (car err)) | |
163 | (message "Error data: %S" (cdr err)) | |
164 | (when tagvalue | |
165 | (setf (cadr err) (append (cadr err) (list :tag tagvalue)))) | |
166 | (message "New error data: %S" (cdr err)) | |
167 | (signal (car err) (cdr err)))))) | |
168 | ||
169 | (defun test-ido-ubiquitous-expected-mode (override &optional tag) | |
170 | "Test whether observed ido-ubiquitous behavior matches OVERRIDE." | |
171 | (declare (indent 1)) | |
172 | (if (eq override 'disable) | |
173 | (progn | |
174 | (should-with-tag | |
175 | ;; Verify that we get standard completion | |
176 | (string= | |
177 | "g" | |
178 | (with-simulated-input "g RET" | |
179 | (completing-read "Prompt: " '("blue" "yellow" "green")))) | |
180 | :tag tag) | |
181 | (should-with-tag | |
182 | (string= | |
183 | "green" | |
184 | (with-simulated-input "g RET" | |
185 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
186 | :tag tag) | |
187 | ;; Standard completion should refuse to finish with incomplete | |
188 | ;; input if match is required | |
189 | (should-error-with-tag | |
190 | (with-simulated-input "b RET" | |
191 | (completing-read "Prompt: " '("brown" "blue" "yellow" "green") nil t)) | |
192 | :type 'error | |
193 | :tag tag)) | |
194 | ;; Common tests whenever ido-ubiquitous is enabled in any way | |
195 | (should-with-tag | |
196 | ;; Verify that ido completion is active | |
197 | (string= | |
198 | "green" | |
199 | (with-simulated-input "g RET" | |
200 | (completing-read "Prompt: " '("blue" "yellow" "green")))) | |
201 | :tag tag) | |
202 | ;; Verify that C-j is working correctly | |
203 | (should-with-tag | |
204 | (string= | |
205 | "g" | |
206 | (with-simulated-input "g C-j" | |
207 | (completing-read "Prompt: " '("blue" "yellow" "green")))) | |
208 | :tag tag) | |
209 | (let ((collection '("brown" "blue" "yellow" "green"))) | |
210 | (should-with-tag | |
211 | (member | |
212 | (with-simulated-input "b RET" | |
213 | (completing-read "Prompt: " collection)) | |
214 | (all-completions "b" collection)) | |
215 | :tag tag)) | |
216 | (cl-case override | |
217 | (enable | |
218 | ;; Test for new style | |
219 | (should-with-tag | |
220 | (string= | |
221 | "blue" | |
222 | (with-simulated-input "RET" | |
223 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
224 | :tag tag) | |
225 | (should-with-tag | |
226 | (string= | |
227 | "" | |
228 | (with-simulated-input "C-j" | |
229 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
230 | :tag tag)) | |
231 | (enable-old | |
232 | (should-with-tag | |
233 | (string= | |
234 | "" | |
235 | (with-simulated-input "RET" | |
236 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
237 | :tag tag) | |
238 | (should-with-tag | |
239 | (string= | |
240 | "blue" | |
241 | (with-simulated-input "C-j" | |
242 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
243 | :tag tag) | |
244 | ;; Verify that doing other stuff reverts RET and C-j to standard | |
245 | ;; meanings | |
246 | (should-with-tag | |
247 | (string= | |
248 | "blue" | |
249 | (with-simulated-input "g DEL RET" | |
250 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
251 | :tag tag) | |
252 | (should-with-tag | |
253 | (string= | |
254 | "blue" | |
255 | (with-simulated-input "<right> <left> RET" | |
256 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
257 | :tag tag) | |
258 | (should-with-tag | |
259 | (string= | |
260 | "" | |
261 | (with-simulated-input "g DEL C-j" | |
262 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
263 | :tag tag) | |
264 | (should-with-tag | |
265 | (string= | |
266 | "" | |
267 | (with-simulated-input "<right> <left> C-j" | |
268 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
269 | :tag tag)) | |
270 | (otherwise (error "Unknown override %S" override))))) | |
271 | ||
272 | (defvar original-completing-read (symbol-function #'completing-read)) | |
273 | ||
274 | (defun test-ido-ubiquitous-expected-mode-on-functional-collection (override &optional tag) | |
275 | "Test whether observed ido-ubiquitous behavior on functional collection matches OVERRIDE." | |
276 | (declare (indent 1)) | |
277 | ;; This just temporarily replaces `completing-read' with a wrapper | |
278 | ;; that always converts the collection argument to an equivalent | |
279 | ;; function. That way, any use of `completing-read' will always see | |
280 | ;; a functional collection. | |
281 | (cl-letf (((symbol-function 'completing-read) | |
282 | (lambda (prompt collection &rest args) | |
283 | (apply original-completing-read prompt | |
284 | (collection-as-function collection) | |
285 | args)))) | |
286 | (test-ido-ubiquitous-expected-mode override tag))) | |
287 | ||
288 | (ert-deftest ido-ubiquitous-test-simple () | |
289 | :tags '(ido ido-ubiquitous) | |
290 | "Test that basic ido-ubiquitous functionality is working." | |
291 | (with-ido-ubiquitous-standard-env | |
292 | (ido-ubiquitous-mode 1) | |
293 | (test-ido-ubiquitous-expected-mode 'enable | |
294 | :simple-enable) | |
295 | (ido-ubiquitous-mode 0) | |
296 | (test-ido-ubiquitous-expected-mode 'disable | |
297 | :simple-disable))) | |
298 | ||
299 | (ert-deftest ido-ubiquitous-test-oldstyle () | |
300 | :tags '(ido ido-ubiquitous) | |
301 | "Test whether old-style completion works as expected." | |
302 | (with-ido-ubiquitous-standard-env | |
303 | (let ((ido-ubiquitous-default-state 'enable-old)) | |
304 | (test-ido-ubiquitous-expected-mode 'enable-old | |
305 | :simple-oldstyle)))) | |
306 | ||
307 | (ert-deftest ido-ubiquitous-test-maxitems () | |
308 | :tags '(ido ido-ubiquitous) | |
309 | "Test whether the large-collection fallback works." | |
310 | (with-ido-ubiquitous-standard-env | |
311 | (let ((ido-cr+-max-items -1)) | |
312 | (test-ido-ubiquitous-expected-mode 'disable | |
313 | :maxitems)))) | |
314 | ||
315 | (ert-deftest ido-ubiquitous-test-override () | |
316 | :tags '(ido ido-ubiquitous) | |
317 | "Test whether ido-ubiquitous overrides work." | |
318 | (with-ido-ubiquitous-standard-env | |
319 | (ido-ubiquitous-with-override 'enable | |
320 | (test-ido-ubiquitous-expected-mode 'enable | |
321 | :override-enable)) | |
322 | (ido-ubiquitous-with-override 'enable-old | |
323 | (test-ido-ubiquitous-expected-mode 'enable-old | |
324 | :override-enable-old)) | |
325 | (ido-ubiquitous-with-override 'disable | |
326 | (test-ido-ubiquitous-expected-mode 'disable | |
327 | :override-disable)))) | |
328 | ||
329 | (ert-deftest ido-ubiquitous-test-functional-collection () | |
330 | :tags '(ido ido-ubiquitous) | |
331 | "Test whether ido-ubiquitous overrides work when collection is a function." | |
332 | (with-ido-ubiquitous-standard-env | |
333 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'disable | |
334 | :collfunc) | |
335 | (ido-ubiquitous-with-override 'enable | |
336 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable | |
337 | :override-enable-collfunc)) | |
338 | (ido-ubiquitous-with-override 'enable-old | |
339 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable-old | |
340 | :override-enable-old-collfunc)))) | |
341 | ||
342 | (ert-deftest ido-cr+-require-match () | |
343 | :tags '(ido ido-cr+) | |
344 | "Test whether require-match works." | |
345 | (with-ido-ubiquitous-standard-env | |
346 | ;; "C-j" should be allowed to return an empty string even if | |
347 | ;; require-match is non-nil, as long as default is nil | |
348 | (should | |
349 | (string= | |
350 | "" | |
351 | (with-simulated-input "C-j" | |
352 | (ido-completing-read+ | |
353 | "Prompt: " | |
354 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))) | |
355 | ;; "C-j" should NOT be allowed to return an empty string if | |
356 | ;; require-match and default are both non-nil. | |
357 | (should-error | |
358 | (with-simulated-input "C-j" | |
359 | (ido-completing-read+ | |
360 | "Prompt: " | |
361 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t nil nil "yellow"))) | |
362 | ;; Multiple presses of C-j won't just select the first match | |
363 | (should-error | |
364 | (with-simulated-input "b C-j C-j C-j" | |
365 | (ido-completing-read+ | |
366 | "Prompt: " | |
367 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))) | |
368 | ;; First press of C-j should complete unique common prefix after the | |
369 | ;; first b, but then get stuck on the choice for the second b. | |
370 | (should-error | |
371 | (with-simulated-input "b C-j b C-j C-j" | |
372 | (ido-completing-read+ | |
373 | "Prompt: " | |
374 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))) | |
375 | ;; This should complete to "blueberry" via 2 rounds of unique common | |
376 | ;; prefix completion, and then return on the 3rd "C-j" | |
377 | (should | |
378 | (string= | |
379 | "blueberry" | |
380 | (with-simulated-input "b C-j b C-j e C-j C-j" | |
381 | (ido-completing-read+ | |
382 | "Prompt: " | |
383 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))) | |
384 | ;; The "C-j" should complete to "bluegrass" and return, because | |
385 | ;; `ido-confirm-unique-completion is nil. | |
386 | (should | |
387 | (string= | |
388 | "bluegrass" | |
389 | (with-simulated-input "b l u e g C-j" | |
390 | (ido-completing-read+ | |
391 | "Prompt: " | |
392 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))) | |
393 | (let ((ido-confirm-unique-completion t)) | |
394 | ;; Now the first "C-j" should complete to "bluegrass" but should | |
395 | ;; not return. | |
396 | (should-error | |
397 | (with-simulated-input "b l u e g C-j" | |
398 | (ido-completing-read+ | |
399 | "Prompt: " | |
400 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))) | |
401 | ;; The first "C-j" should complete to "bluegrass", and the second | |
402 | ;; should return. | |
403 | (should | |
404 | (string= | |
405 | "bluegrass" | |
406 | (with-simulated-input "b l u e g C-j C-j" | |
407 | (ido-completing-read+ | |
408 | "Prompt: " | |
409 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))))) | |
410 | ;; Finally, a few tests for the expected wrong behavior without | |
411 | ;; ido-cr+. If ido.el ever fixes this bug, it will cause this test | |
412 | ;; to fail as a signal that the workaround can be phased out. | |
413 | (should | |
414 | (string= | |
415 | "" | |
416 | (with-simulated-input "C-j" | |
417 | (ido-completing-read | |
418 | "Prompt: " | |
419 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))) | |
420 | (should | |
421 | (string= | |
422 | "b" | |
423 | (with-simulated-input "b C-j" | |
424 | (ido-completing-read | |
425 | "Prompt: " | |
426 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))))) | |
427 | ||
428 | ;; Functions to define overrides on for testing | |
429 | (defun idu-no-override-testfunc () | |
430 | (test-ido-ubiquitous-expected-mode 'enable | |
431 | :func-override-none) | |
432 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'disable | |
433 | :func-override-none-collfunc)) | |
434 | (defun idu-enabled-testfunc (&rest args) | |
435 | (test-ido-ubiquitous-expected-mode 'enable | |
436 | :func-override-enable) | |
437 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable | |
438 | :func-override-enable-collfunc)) | |
439 | (defun idu-disabled-testfunc (&rest args) | |
440 | (test-ido-ubiquitous-expected-mode 'disable | |
441 | :func-override-disable) | |
442 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'disable | |
443 | :func-override-disable-collfunc)) | |
444 | (defun idu-enabled-oldstyle-testfunc (&rest args) | |
445 | (test-ido-ubiquitous-expected-mode 'enable-old | |
446 | :func-override-enable-old) | |
447 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable-old | |
448 | :func-override-enable-old-collfunc)) | |
449 | ||
450 | ;; commands to define overrides on for testing | |
451 | (defun idu-no-override-testcmd (&rest args) | |
452 | (interactive | |
453 | (list | |
454 | (test-ido-ubiquitous-expected-mode 'enable | |
455 | :cmd-override-none) | |
456 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'disable | |
457 | :cmd-override-none-collfunc))) | |
458 | (test-ido-ubiquitous-expected-mode 'enable | |
459 | :cmd-override-none) | |
460 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'disable | |
461 | :cmd-override-non-collfunc)) | |
462 | (defun idu-enabled-testcmd (&rest args) | |
463 | (interactive | |
464 | (list | |
465 | (test-ido-ubiquitous-expected-mode 'enable | |
466 | :cmd-override-enable) | |
467 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable | |
468 | :cmd-override-enable-collfunc))) | |
469 | (test-ido-ubiquitous-expected-mode 'enable | |
470 | :cmd-override-enable) | |
471 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable | |
472 | :cmd-override-enable-collfunc)) | |
473 | (defun idu-disabled-testcmd (&rest args) | |
474 | (interactive | |
475 | (list | |
476 | (test-ido-ubiquitous-expected-mode 'disable | |
477 | :cmd-override-disable) | |
478 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'disable | |
479 | :cmd-override-disable-collfunc))) | |
480 | (test-ido-ubiquitous-expected-mode 'disable | |
481 | :cmd-override-disable) | |
482 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'disable | |
483 | :cmd-override-disable-collfunc)) | |
484 | (defun idu-enabled-oldstyle-testcmd (&rest args) | |
485 | (interactive | |
486 | (list | |
487 | (test-ido-ubiquitous-expected-mode 'enable-old | |
488 | :cmd-override-enable-old) | |
489 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable-old | |
490 | :cmd-override-enable-old-collfunc))) | |
491 | (test-ido-ubiquitous-expected-mode 'enable-old | |
492 | :cmd-override-enable-old) | |
493 | (test-ido-ubiquitous-expected-mode-on-functional-collection 'enable-old | |
494 | :cmd-override-enable-old-collfunc)) | |
495 | ||
496 | (ert-deftest ido-ubiquitous-test-command-and-function-overrides () | |
497 | :tags '(ido ido-ubiquitous) | |
498 | "Test whether command- and function-specific overrides work." | |
499 | (let ((orig-func-overrides ido-ubiquitous-function-overrides) | |
500 | (orig-cmd-overrides ido-ubiquitous-command-overrides)) | |
501 | (unwind-protect | |
502 | (with-ido-ubiquitous-standard-env | |
503 | (customize-set-variable | |
504 | 'ido-ubiquitous-function-overrides | |
505 | (append ido-ubiquitous-function-overrides | |
506 | '((enable exact "idu-enabled-testfunc") | |
507 | (disable exact "idu-disabled-testfunc") | |
508 | (enable-old exact "idu-enabled-oldstyle-testfunc")))) | |
509 | (cl-loop for func in | |
510 | '(idu-no-override-testfunc | |
511 | idu-enabled-testfunc | |
512 | idu-disabled-testfunc | |
513 | idu-enabled-oldstyle-testfunc) | |
514 | do (funcall func)) | |
515 | (customize-set-variable | |
516 | 'ido-ubiquitous-command-overrides | |
517 | (append ido-ubiquitous-command-overrides | |
518 | '((enable exact "idu-enabled-testcmd") | |
519 | (disable exact "idu-disabled-testcmd") | |
520 | (enable-old exact "idu-enabled-oldstyle-testcmd")))) | |
521 | (cl-loop for cmd in | |
522 | '(idu-no-override-testcmd | |
523 | idu-enabled-testcmd | |
524 | idu-disabled-testcmd | |
525 | idu-enabled-oldstyle-testcmd) | |
526 | do (call-interactively cmd))) | |
527 | (customize-set-variable 'ido-ubiquitous-function-overrides orig-func-overrides) | |
528 | (customize-set-variable 'ido-ubiquitous-command-overrides orig-cmd-overrides)))) | |
529 | ||
530 | (ert-deftest ido-ubiquitous-test-fallback () | |
531 | :tags '(ido ido-ubiquitous) | |
532 | "Test whether manually invoking fallback works." | |
533 | (with-ido-ubiquitous-standard-env | |
534 | (should | |
535 | ;; C-b/f not at beginning/end of input should not fall back | |
536 | (string= | |
537 | "green" | |
538 | (with-simulated-input "g C-b C-f RET" | |
539 | (completing-read "Prompt: " '("blue" "yellow" "green"))))) | |
540 | (should | |
541 | ;; C-f at end of input should fall back | |
542 | (string= | |
543 | "g" | |
544 | (with-simulated-input "g C-f RET" | |
545 | (completing-read "Prompt: " '("blue" "yellow" "green"))))) | |
546 | (should | |
547 | ;; Repeated C-b should not fall back | |
548 | (string= | |
549 | "green" | |
550 | (with-simulated-input "g C-b C-b C-b C-b RET" | |
551 | (completing-read "Prompt: " '("blue" "yellow" "green"))))) | |
552 | (should | |
553 | ;; C-b at beginning of line should fall back (if previous action | |
554 | ;; was not also C-b) | |
555 | (string= | |
556 | "g" | |
557 | (with-simulated-input "g C-b x DEL C-b RET" | |
558 | (completing-read "Prompt: " '("blue" "yellow" "green"))))))) | |
559 | ||
560 | (defun ido-ubiquitous-run-all-tests () | |
561 | (interactive) | |
562 | (ert "^ido-\\(ubiquitous\\|cr\\+\\)-")) | |
563 | ||
564 | (provide 'ido-ubiquitous-test) | |
565 | ||
566 | ;;; ido-ubiquitous-test.el ends here |
0 | ;;; test-helper.el --- -*- lexical-binding: t -*- | |
1 | ||
2 | ;; Copyright (C) 2015 Ryan C. Thompson | |
3 | ||
4 | ;; Filename: test-helper.el | |
5 | ;; Author: Ryan C. Thompson | |
6 | ;; Created: Sat Nov 21 15:27:00 2015 (-0800) | |
7 | ||
8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
9 | ;; | |
10 | ;; This program is free software: you can redistribute it and/or modify | |
11 | ;; it under the terms of the GNU General Public License as published by | |
12 | ;; the Free Software Foundation, either version 3 of the License, or (at | |
13 | ;; your option) any later version. | |
14 | ;; | |
15 | ;; This program is distributed in the hope that it will be useful, but | |
16 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | ;; General Public License for more details. | |
19 | ;; | |
20 | ;; You should have received a copy of the GNU General Public License | |
21 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
22 | ;; | |
23 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
24 | ;; | |
25 | ;;; Code: | |
26 | ||
27 | (require 'f) | |
28 | ||
29 | (defvar test-path | |
30 | (f-dirname (f-this-file))) | |
31 | ||
32 | (defvar code-path | |
33 | (f-parent test-path)) | |
34 | ||
35 | (add-to-list 'load-path code-path) | |
36 | ||
37 | (require 'ido-completing-read+) | |
38 | (require 'ido-ubiquitous) | |
39 | ||
40 | ;;; test-helper.el ends here |
0 | ;;; -*- lexical-binding: t -*- | |
1 | ||
2 | (require 'ido) | |
3 | (require 'ido-completing-read+) | |
4 | (require 'buttercup) | |
5 | (require 'cl-lib) | |
6 | (require 'with-simulated-input) | |
7 | ||
8 | (defun collection-as-function (collection) | |
9 | "Return a function equivalent to COLLECTION. | |
10 | ||
11 | The returned function will work equivalently to COLLECTION when | |
12 | passed to `all-completions' and `try-completion'." | |
13 | (completion-table-dynamic (lambda (string) (all-completions string collection)))) | |
14 | ||
15 | (defun shadow-var (var &optional temp-value) | |
16 | "Shadow the value of VAR. | |
17 | ||
18 | This will push the current value of VAR to VAR's | |
19 | `shadowed-values' property, and then set it to TEMP-VALUE. To | |
20 | reverse this process, call `unshadow-var' on VAR. Vars can | |
21 | be shadowed recursively, and must be unshadowed once for each | |
22 | shadowing in order to restore the original value. You can think | |
23 | of shadowing as dynamic binding with `let', but with manual | |
24 | control over when bindings start and end. | |
25 | ||
26 | If VAR is a Custom variable (see `custom-variable-p'), it will be | |
27 | set using `customize-set-variable', and if TEMP-VALUE is nil it | |
28 | will be replaces with VAR's standard value. | |
29 | ||
30 | Other variables will be set with `set-default', and a TEMP-VALUE | |
31 | of nil will not be treated specially. | |
32 | ||
33 | `shadow-var' only works on variables declared as special (i.e. | |
34 | using `defvar' or similar). It will not work on lexically bound | |
35 | variables." | |
36 | (unless (special-variable-p var) | |
37 | (error "Cannot shadow lexical var `%s'" var)) | |
38 | (let* ((use-custom (custom-variable-p var)) | |
39 | (setter (if use-custom 'customize-set-variable 'set-default)) | |
40 | (temp-value (or temp-value | |
41 | (and use-custom | |
42 | (eval (car (get var 'standard-value))))))) | |
43 | ;; Push the current value on the stack | |
44 | (push (symbol-value var) (get var 'shadowed-values)) | |
45 | (funcall setter var temp-value))) | |
46 | ||
47 | (defun var-shadowed-p (var) | |
48 | "Return non-nil if VAR is shadowed by `shadow-var'." | |
49 | ;; We don't actually want to return that list if it's non-nil. | |
50 | (and (get var 'shadowed-values) t)) | |
51 | ||
52 | (defun unshadow-var (var) | |
53 | "Reverse the last call to `shadow-var' on VAR." | |
54 | (if (var-shadowed-p var) | |
55 | (let* ((use-custom (custom-variable-p var)) | |
56 | (setter (if use-custom 'customize-set-variable 'set-default)) | |
57 | (value (pop (get var 'shadowed-values)))) | |
58 | (funcall setter var value)) | |
59 | (error "Var is not shadowed: %s" var))) | |
60 | ||
61 | (defun fully-unshadow-var (var) | |
62 | "Reverse *all* calls to `shadow-var' on VAR." | |
63 | (when (var-shadowed-p var) | |
64 | (let* ((use-custom (custom-variable-p var)) | |
65 | (setter (if use-custom 'customize-set-variable 'set-default)) | |
66 | (value (car (last (get var 'shadowed-values))))) | |
67 | (put var 'shadowed-values nil) | |
68 | (funcall setter var value)))) | |
69 | ||
70 | (defun fully-unshadow-all-vars (&optional vars) | |
71 | "Reverse *all* calls to `shadow-var' on VARS. | |
72 | ||
73 | If VARS is nil, unshadow *all* variables." | |
74 | (if vars | |
75 | (mapc #'fully-unshadow-var vars) | |
76 | (mapatoms #'fully-unshadow-var)) | |
77 | nil) | |
78 | ||
79 | (defmacro shadow-vars (varlist) | |
80 | "Shadow a list of vars with new values. | |
81 | ||
82 | VARLIST describes the variables to be shadowed with the same | |
83 | syntax as `let'. | |
84 | ||
85 | See `shadow-var'." | |
86 | (declare (indent 0)) | |
87 | (cl-loop | |
88 | with var = nil | |
89 | with value = nil | |
90 | for binding in varlist | |
91 | if (symbolp binding) | |
92 | do (setq var binding | |
93 | value nil) | |
94 | else | |
95 | do (setq var (car binding) | |
96 | value (cadr binding)) | |
97 | collect `(shadow-var ',var ,value) into exprs | |
98 | finally return `(progn ,@exprs))) | |
99 | ||
100 | (defmacro unshadow-vars (vars) | |
101 | "Un-shadow a list of VARS. | |
102 | ||
103 | This is a macro for consistency with `shadow-vars', but it will | |
104 | also accept a quoted list for the sake of convenience." | |
105 | (declare (indent 0)) | |
106 | (when (eq (car vars) 'quote) | |
107 | (setq vars (eval vars))) | |
108 | `(mapc #'unshadow-var ',vars)) | |
109 | ||
110 | (describe "Within the `ido-completing-read+' package" | |
111 | ||
112 | ;; Reset all of these variables to their standard values before each | |
113 | ;; test, saving the previous values for later restoration. | |
114 | (before-each | |
115 | (shadow-vars | |
116 | ((ido-mode t) | |
117 | (ido-ubiquitous-mode t) | |
118 | ido-cr+-debug-mode | |
119 | ido-cr+-auto-update-blacklist | |
120 | ido-cr+-fallback-function | |
121 | ido-cr+-max-items | |
122 | ido-cr+-function-blacklist | |
123 | ido-cr+-function-whitelist | |
124 | ido-cr+-nil-def-alternate-behavior-list | |
125 | ido-cr+-replace-completely | |
126 | ido-confirm-unique-completion | |
127 | ido-enable-flex-matching))) | |
128 | ||
129 | ;; Restore the saved values after each test | |
130 | (after-each | |
131 | (fully-unshadow-all-vars)) | |
132 | ||
133 | (describe "the `ido-completing-read+' function" | |
134 | ||
135 | (it "should complete with a matching item on RET" | |
136 | (expect | |
137 | (with-simulated-input "g RET" | |
138 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
139 | :to-equal "green")) | |
140 | (it "should complete with the first match when multiple matches are available" | |
141 | (expect | |
142 | (with-simulated-input "b RET" | |
143 | (ido-completing-read+ "Prompt: " '("brown" "blue" "yellow" "green"))) | |
144 | :to-equal "brown")) | |
145 | (it "should allow <left> and <right> to cycle completions, with wrap-around" | |
146 | (expect | |
147 | (with-simulated-input "b <right> <right> <right> <right> <left> RET" | |
148 | (ido-completing-read+ "Prompt: " '("brown" "blue" "yellow" "green"))) | |
149 | :to-equal | |
150 | "blue")) | |
151 | ||
152 | (it "should return \"\" when RET or C-j is pressed on an empty input even when REQUIRE-MATCH is non-nil" | |
153 | ;; No REQUIRE-MATCH | |
154 | (expect | |
155 | (with-simulated-input "RET" | |
156 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
157 | :to-equal "blue") | |
158 | (expect | |
159 | (with-simulated-input "C-j" | |
160 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
161 | :to-equal "") | |
162 | ;; Again, with REQUIRE-MATCH | |
163 | (expect | |
164 | (with-simulated-input "RET" | |
165 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil t)) | |
166 | :to-equal "") | |
167 | (expect | |
168 | (with-simulated-input "C-j" | |
169 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil t)) | |
170 | :to-equal "")) | |
171 | ||
172 | ;; Verify that DEF works, whether or not it is an element of | |
173 | ;; COLLECTION | |
174 | (it "should accept all the same forms of DEF as `completing-read-default'" | |
175 | (expect | |
176 | (with-simulated-input "RET" | |
177 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil nil nil "green")) | |
178 | :to-equal "green") | |
179 | (expect | |
180 | (with-simulated-input "RET" | |
181 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil t nil nil "green")) | |
182 | :to-equal "green") | |
183 | (expect | |
184 | (with-simulated-input "RET" | |
185 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil nil nil nil "brown")) | |
186 | :to-equal "brown") | |
187 | (expect | |
188 | (with-simulated-input "RET" | |
189 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil t nil nil "brown")) | |
190 | :to-equal "brown") | |
191 | (expect | |
192 | (with-simulated-input "RET" | |
193 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil t nil nil '("brown" "green"))) | |
194 | :to-equal "brown")) | |
195 | ||
196 | ;; Verify that INITIAL-INPUT works | |
197 | (it "should work with INITIAL-INPUT" | |
198 | (expect | |
199 | (with-simulated-input "RET" | |
200 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil "gr")) | |
201 | :to-equal "green")) | |
202 | ||
203 | ;; Verify that INITIAL-INPUT and DEF don't interfere with each other | |
204 | (it "should properly handle both INITIAL-INPUT and DEF at the same time" | |
205 | (expect | |
206 | (with-simulated-input "RET" | |
207 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil "gr" nil "blue")) | |
208 | :to-equal "green") | |
209 | (expect | |
210 | (with-simulated-input "DEL DEL RET" | |
211 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil "gr" nil "blue")) | |
212 | :to-equal "blue")) | |
213 | ||
214 | ;; Verify that ido-cr+ works on function collections | |
215 | (it "should work when COLLECTION is a function" | |
216 | (expect | |
217 | (with-simulated-input "g RET" | |
218 | (ido-completing-read+ "Prompt: " (collection-as-function '("blue" "yellow" "green")))) | |
219 | :to-equal "green")) | |
220 | ||
221 | (describe "when `ido-cr+-max-items' is set" | |
222 | (it "should not trigger a fallback for small collections" | |
223 | (expect | |
224 | (with-simulated-input "g RET" | |
225 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
226 | :to-equal "green")) | |
227 | (it "should trigger a fallback for large collections" | |
228 | (expect | |
229 | ;; With max-items negative, all collections are considered "too | |
230 | ;; large" | |
231 | (let ((ido-cr+-max-items -1)) | |
232 | (with-simulated-input "g RET" | |
233 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))) | |
234 | :to-equal "g"))) | |
235 | ||
236 | (describe "when REQUIRE-MATCH is non-nil" | |
237 | (it "should still allow exiting with an empty string if DEF is nil" | |
238 | (expect | |
239 | (with-simulated-input "C-j" | |
240 | (ido-completing-read+ | |
241 | "Prompt: " | |
242 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)) | |
243 | :to-equal "")) | |
244 | ;; "C-j" should NOT be allowed to return an empty string if | |
245 | ;; require-match and default are both non-nil. | |
246 | (it "should not alow exiting with an empty string if DEF is non-nil" | |
247 | (expect | |
248 | (with-simulated-input "C-j" | |
249 | (ido-completing-read+ | |
250 | "Prompt: " | |
251 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t nil nil "yellow")) | |
252 | :to-throw)) | |
253 | (it "shouldn't allow C-j to select an ambiguous match" | |
254 | (expect | |
255 | (with-simulated-input "b C-j C-j C-j" | |
256 | (ido-completing-read+ | |
257 | "Prompt: " | |
258 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)) | |
259 | :to-throw) | |
260 | ;; First press of C-j should complete to "blue" after the | |
261 | ;; first b, but then get stuck on the choice for the second b. | |
262 | (expect | |
263 | (with-simulated-input "b C-j b C-j C-j C-j" | |
264 | (ido-completing-read+ | |
265 | "Prompt: " | |
266 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow" "green") nil t)) | |
267 | :to-throw)) | |
268 | (it "should allow exiting with an unambiguous match" | |
269 | (expect | |
270 | (with-simulated-input "b C-j b C-j e C-j C-j" | |
271 | (ido-completing-read+ | |
272 | "Prompt: " | |
273 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow" "green") nil t)) | |
274 | :to-equal "blueberry") | |
275 | ;; The "C-j" should complete to "bluegrass" and return, because | |
276 | ;; `ido-confirm-unique-completion is nil. | |
277 | (expect | |
278 | (with-simulated-input "b l u e g C-j" | |
279 | (ido-completing-read+ | |
280 | "Prompt: " | |
281 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)) | |
282 | :to-equal "bluegrass")) | |
283 | (it "should require an extra C-j to exit when `ido-confirm-unique-completion' is non-nil" | |
284 | (setq ido-confirm-unique-completion t) | |
285 | ;; Now the first "C-j" should complete to "bluegrass" but should | |
286 | ;; not return. | |
287 | (expect | |
288 | (with-simulated-input "b l u e g C-j" | |
289 | (ido-completing-read+ | |
290 | "Prompt: " | |
291 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)) | |
292 | :to-throw) | |
293 | ;; The first "C-j" should complete to "bluegrass", and the second | |
294 | ;; should return. | |
295 | (expect | |
296 | (with-simulated-input "b l u e g C-j C-j" | |
297 | (ido-completing-read+ | |
298 | "Prompt: " | |
299 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)) | |
300 | :to-equal "bluegrass")) | |
301 | ||
302 | ;; Finally, a test for the expected wrong behavior without | |
303 | ;; ido-cr+. If ido.el ever fixes this bug, it will cause this test | |
304 | ;; to fail as a signal that the workaround can be phased out. | |
305 | (it "should return a non-match when ordinary `ido-completing-read' is used" | |
306 | (expect | |
307 | (with-simulated-input "b C-j" | |
308 | (ido-completing-read | |
309 | "Prompt: " | |
310 | '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)) | |
311 | :to-equal "b"))) | |
312 | ||
313 | (describe "with manual fallback shortcuts" | |
314 | (it "should not fall back when C-b or C-f is used in the middle of the input" | |
315 | (expect | |
316 | ;; C-b/f not at beginning/end of input should not fall back | |
317 | (with-simulated-input "g C-b C-f RET" | |
318 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
319 | :to-equal "green")) | |
320 | (it "should fall back on C-f at end of input" | |
321 | (expect | |
322 | ;; C-f at end of input should fall back | |
323 | (with-simulated-input "g C-f RET" | |
324 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
325 | :to-equal "g")) | |
326 | (it "should not fall back from repeated C-b that hits the start of input" | |
327 | (expect | |
328 | ;; Repeated C-b should not fall back | |
329 | (with-simulated-input "g C-b C-b C-b C-b RET" | |
330 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
331 | :to-equal "green")) | |
332 | (it "should fall back on C-b at beginning of input (if previous action was not C-b)" | |
333 | (expect | |
334 | ;; C-b at beginning of line should fall back (if previous action | |
335 | ;; was not also C-b) | |
336 | (with-simulated-input "g C-b x DEL C-b RET" | |
337 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))) | |
338 | :to-equal "g"))) | |
339 | ||
340 | (describe "with a workaround for an bug with non-nil `ido-enable-dot-prefix'" | |
341 | ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=26997 | |
342 | ;; for more information on this bug. | |
343 | (before-each | |
344 | (setq ido-enable-dot-prefix t)) | |
345 | (it "should not throw an error when \"\" is in the collection" | |
346 | (expect | |
347 | (with-simulated-input "RET" | |
348 | (ido-completing-read+ "Pick: " '("" "aaa" "aab" "aac"))) | |
349 | :to-equal "") | |
350 | (expect | |
351 | (with-simulated-input "a a b RET" | |
352 | (ido-completing-read+ "Pick: " '("" "aaa" "aab" "aac"))) | |
353 | :to-equal "aab"))) | |
354 | ||
355 | (describe "with dynamic collections" | |
356 | (before-all | |
357 | (setq my-dynamic-collection | |
358 | (completion-table-dynamic | |
359 | (lambda (text) | |
360 | (cond | |
361 | ;; Sub-completions for "hello" | |
362 | ((s-prefix-p "hello" text) | |
363 | '("hello" "hello-world" "hello-everyone" "hello-universe")) | |
364 | ;; Sub-completions for "goodbye" | |
365 | ((s-prefix-p "goodbye" text) | |
366 | '("goodbye" "goodbye-world" "goodbye-everyone" "goodbye-universe")) | |
367 | ;; General completions | |
368 | (t | |
369 | '("hello" "goodbye" "helicopter" "helium" "goodness" "goodwill"))))))) | |
370 | (after-all | |
371 | (setq my-dynamic-collection nil)) | |
372 | (before-each | |
373 | (setq ido-enable-flex-matching t | |
374 | ido-confirm-unique-completion nil) | |
375 | (spy-on 'ido-cr+-update-dynamic-collection | |
376 | :and-call-through)) | |
377 | ||
378 | (it "should allow selection of dynamically-added completions" | |
379 | (expect | |
380 | (with-simulated-input "hello- RET" | |
381 | (ido-completing-read+ "Say something: " my-dynamic-collection)) | |
382 | :to-equal "hello-world") | |
383 | (expect 'ido-cr+-update-dynamic-collection | |
384 | :to-have-been-called)) | |
385 | ||
386 | (it "should allow ido flex-matching of dynamically-added completions" | |
387 | (expect | |
388 | (with-simulated-input "hello-ld RET" | |
389 | (ido-completing-read+ "Say something: " my-dynamic-collection)) | |
390 | :to-equal | |
391 | "hello-world") | |
392 | (expect 'ido-cr+-update-dynamic-collection | |
393 | :to-have-been-called)) | |
394 | (it "should do a dynamic update when pressing TAB" | |
395 | (expect | |
396 | (with-simulated-input "h TAB -ld RET" | |
397 | (ido-completing-read+ "Say something: " my-dynamic-collection)) | |
398 | :to-equal | |
399 | "hello-world") | |
400 | (expect 'ido-cr+-update-dynamic-collection | |
401 | :to-have-been-called)) | |
402 | (it "should do a dynamic update when idle" | |
403 | (expect | |
404 | (with-simulated-input | |
405 | '("h" | |
406 | (wsi-simulate-idle-time (1+ ido-cr+-dynamic-update-idle-time)) | |
407 | "-ld RET") | |
408 | (ido-completing-read+ "Say something: " my-dynamic-collection)) | |
409 | :to-equal | |
410 | "hello-world") | |
411 | (expect 'ido-cr+-update-dynamic-collection | |
412 | :to-have-been-called)) | |
413 | (it "should do a dynamic update when there is only one match remaining" | |
414 | (expect | |
415 | (with-simulated-input "hell-ld RET" | |
416 | (ido-completing-read+ "Say something: " my-dynamic-collection)) | |
417 | :to-equal | |
418 | "hello-world") | |
419 | (expect 'ido-cr+-update-dynamic-collection | |
420 | :to-have-been-called)) | |
421 | (it "should not exit with a unique match if new matches are dynamically added" | |
422 | (expect | |
423 | (with-simulated-input '("hell TAB -ld RET") | |
424 | (ido-completing-read+ "Say something: " my-dynamic-collection)) | |
425 | :to-equal | |
426 | "hello-world") | |
427 | (expect 'ido-cr+-update-dynamic-collection | |
428 | :to-have-been-called)) | |
429 | (it "should exit with a match that is still unique after dynamic updating" | |
430 | (expect | |
431 | (with-simulated-input '("helic TAB") | |
432 | (ido-completing-read+ "Say something: " my-dynamic-collection)) | |
433 | :to-equal | |
434 | "helicopter") | |
435 | (expect 'ido-cr+-update-dynamic-collection | |
436 | :to-have-been-called)) | |
437 | (it "should respect `ido-restrict-to-matches' when doing dynamic updates" | |
438 | (let ((collection | |
439 | (list "aaa-ddd-ggg" "aaa-eee-ggg" "aaa-fff-ggg" | |
440 | "bbb-ddd-ggg" "bbb-eee-ggg" "bbb-fff-ggg" | |
441 | "ccc-ddd-ggg" "ccc-eee-ggg" "ccc-fff-ggg" | |
442 | "aaa-ddd-hhh" "aaa-eee-hhh" "aaa-fff-hhh" | |
443 | "bbb-ddd-hhh" "bbb-eee-hhh" "bbb-fff-hhh" | |
444 | "ccc-ddd-hhh" "ccc-eee-hhh" "ccc-fff-hhh" | |
445 | "aaa-ddd-iii" "aaa-eee-iii" "aaa-fff-iii" | |
446 | "bbb-ddd-iii" "bbb-eee-iii" "bbb-fff-iii" | |
447 | "ccc-ddd-iii" "ccc-eee-iii" "ccc-fff-iii"))) | |
448 | ;; Test the internal function | |
449 | (expect | |
450 | (ido-cr+-apply-restrictions | |
451 | collection | |
452 | (list (cons nil "bbb") | |
453 | (cons nil "eee"))) | |
454 | :to-equal '("bbb-eee-ggg" "bbb-eee-hhh" "bbb-eee-iii")) | |
455 | ||
456 | ;; First verify it without a dynamic collection | |
457 | (expect | |
458 | (with-simulated-input "eee C-SPC bbb C-SPC ggg RET" | |
459 | (ido-completing-read+ | |
460 | "Pick: " collection nil t nil nil (car collection))) | |
461 | :to-equal "bbb-eee-ggg") | |
462 | ;; Now test the same with a dynamic collection | |
463 | (expect | |
464 | (with-simulated-input "eee C-SPC bbb C-SPC ggg RET" | |
465 | (ido-completing-read+ | |
466 | "Pick: " (collection-as-function collection) nil t nil nil (car collection))) | |
467 | :to-equal "bbb-eee-ggg")))) | |
468 | ||
469 | (describe "with unusual inputs" | |
470 | (it "should accept a COLLECTION of symbols" | |
471 | (expect | |
472 | (with-simulated-input "g RET" | |
473 | (ido-completing-read+ "Prompt: " '(blue yellow green))) | |
474 | :to-equal "green")) | |
475 | (it "should accept a mix of strings and symbols in COLLECTION" | |
476 | (expect | |
477 | (with-simulated-input "g RET" | |
478 | (ido-completing-read+ "Prompt: " '(blue "yellow" green))) | |
479 | :to-equal "green")) | |
480 | (it "should accept symbols in DEF" | |
481 | (expect | |
482 | (with-simulated-input "RET" | |
483 | (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil t nil nil '(brown "green"))) | |
484 | :to-equal "brown")) | |
485 | (it "should accept an alist COLLECTION" | |
486 | (expect | |
487 | (with-simulated-input "RET" | |
488 | (ido-completing-read+ | |
489 | "Prompt: " | |
490 | '(("blue" . blue-value) | |
491 | ("yellow" . yellow-value) | |
492 | (green . green-value)) | |
493 | nil nil nil nil "green")) | |
494 | :to-equal "green")) | |
495 | (it "should accept a hash table COLLECTION" | |
496 | (expect | |
497 | (with-simulated-input "RET" | |
498 | (let ((collection (make-hash-table))) | |
499 | (puthash "blue" 'blue-value collection) | |
500 | (puthash "yellow" 'yellow-value collection) | |
501 | (puthash 'green 'green-value collection) | |
502 | (ido-completing-read+ "Prompt: " collection nil nil nil nil "green"))) | |
503 | :to-equal "green")) | |
504 | (it "should accept an obarray COLLECTION" | |
505 | (expect | |
506 | (with-simulated-input "forward-char RET" | |
507 | (ido-completing-read+ "Prompt: " obarray #'commandp | |
508 | t nil nil "backward-char")) | |
509 | :to-equal "forward-char")))) | |
510 | ||
511 | (describe "ido-ubiquitous-mode" | |
512 | ;; Set up a test command that calls `completing-read' | |
513 | (before-all | |
514 | (setf (symbol-function 'test-command) | |
515 | (lambda () | |
516 | (interactive) | |
517 | (completing-read "Prompt: " '("blue" "yellow" "green"))))) | |
518 | ;; Delete the test command | |
519 | (after-all | |
520 | (setf (symbol-function 'test-command) nil)) | |
521 | ||
522 | ;; Verify that the mode can be activated | |
523 | (it "should enable itself properly" | |
524 | (expect | |
525 | (progn | |
526 | (ido-ubiquitous-mode 1) | |
527 | (with-simulated-input "g RET" | |
528 | (command-execute 'test-command))) | |
529 | :to-equal "green")) | |
530 | (it "should disable itself properly" | |
531 | (expect | |
532 | (progn | |
533 | (ido-ubiquitous-mode 0) | |
534 | (with-simulated-input "g RET" | |
535 | (command-execute 'test-command))) | |
536 | :to-equal "g")) | |
537 | ||
538 | (describe "with `ido-cr+-function-blacklist'" | |
539 | (before-all | |
540 | (setf (symbol-function 'blacklisted-command) | |
541 | (lambda (arg) | |
542 | (interactive (list (completing-read "Prompt: " '("blue" "yellow" "green")))) | |
543 | arg) | |
544 | (symbol-function 'blacklisted-function) | |
545 | (lambda () | |
546 | (completing-read "Prompt: " '("blue" "yellow" "green"))) | |
547 | (symbol-function 'cmd-that-calls-blacklisted-function) | |
548 | (lambda () | |
549 | (interactive) | |
550 | (funcall 'blacklisted-function)) | |
551 | (symbol-function 'blacklisted-collection) | |
552 | (collection-as-function '("blue" "yellow" "green")))) | |
553 | (after-all | |
554 | (setf (symbol-function 'blacklisted-command) nil | |
555 | (symbol-function 'blacklisted-function) nil | |
556 | (symbol-function 'cmd-that-calls-blacklisted-function) nil | |
557 | (symbol-function 'blacklisted-collection) nil)) | |
558 | ;; First verify that they work normally before blacklisting them | |
559 | (describe "when the blacklist is empty" | |
560 | (it "should not affect a non-blacklisted command" | |
561 | (expect | |
562 | (with-simulated-input "g RET" | |
563 | (call-interactively 'blacklisted-command)) | |
564 | :to-equal "green")) | |
565 | (it "should not affect a non-blacklisted function" | |
566 | (expect | |
567 | (with-simulated-input "g RET" | |
568 | (call-interactively 'cmd-that-calls-blacklisted-function)) | |
569 | :to-equal "green")) | |
570 | (it "should not affect a non-blacklisted collection" | |
571 | (expect | |
572 | (with-simulated-input "g RET" | |
573 | (ido-completing-read+ "Prompt: " 'blacklisted-collection)) | |
574 | :to-equal "green"))) | |
575 | ||
576 | (describe "when the specified functions are blacklisted" | |
577 | (before-each | |
578 | (setq ido-cr+-function-blacklist | |
579 | (append '(blacklisted-command | |
580 | blacklisted-function | |
581 | blacklisted-collection) | |
582 | ido-cr+-function-blacklist))) | |
583 | (it "should prevent ido in a blacklisted command" | |
584 | (expect | |
585 | (with-simulated-input "g RET" | |
586 | (call-interactively 'blacklisted-command)) | |
587 | :to-equal "g")) | |
588 | (it "should prevent ido in a blacklisted function" | |
589 | (expect | |
590 | (with-simulated-input "g RET" | |
591 | (call-interactively 'cmd-that-calls-blacklisted-function)) | |
592 | :to-equal "g")) | |
593 | (it "should prevent ido with a blacklisted collection" | |
594 | (expect | |
595 | (with-simulated-input "g RET" | |
596 | (ido-completing-read+ "Prompt: " 'blacklisted-collection)) | |
597 | :to-equal "g")))) | |
598 | ||
599 | (describe "with `ido-cr+-function-whitelist'" | |
600 | (before-all | |
601 | (setf (symbol-function 'whitelisted-command) | |
602 | (lambda (arg) | |
603 | (interactive | |
604 | (list | |
605 | (completing-read "Prompt: " '("blue" "yellow" "green")))) | |
606 | arg) | |
607 | (symbol-function 'whitelisted-function) | |
608 | (lambda () | |
609 | (completing-read "Prompt: " '("blue" "yellow" "green"))) | |
610 | (symbol-function 'cmd-that-calls-whitelisted-function) | |
611 | (lambda () | |
612 | (interactive) | |
613 | (funcall 'whitelisted-function)) | |
614 | (symbol-function 'whitelisted-collection) | |
615 | (lambda (string pred action) | |
616 | (complete-with-action action '("blue" "yellow" "green") string pred)))) | |
617 | (after-all | |
618 | (setf (symbol-function 'whitelisted-command) nil | |
619 | (symbol-function 'whitelisted-function) nil | |
620 | (symbol-function 'cmd-that-calls-whitelisted-function) nil | |
621 | (symbol-function 'whitelisted-collection) nil)) | |
622 | (describe "when the whitelist is inactive (i.e. everything is whitelisted)" | |
623 | (before-each | |
624 | (setq ido-cr+-function-whitelist nil)) | |
625 | (it "should enable ido in a command" | |
626 | (expect | |
627 | (with-simulated-input "g RET" | |
628 | (call-interactively 'whitelisted-command)) | |
629 | :to-equal "green")) | |
630 | (it "should enable ido in a function" | |
631 | (expect | |
632 | (with-simulated-input "g RET" | |
633 | (call-interactively 'cmd-that-calls-whitelisted-function)) | |
634 | :to-equal "green")) | |
635 | (it "should enable ido for a collection" | |
636 | (expect | |
637 | (with-simulated-input "g RET" | |
638 | (ido-completing-read+ "Prompt: " 'whitelisted-collection)) | |
639 | :to-equal "green"))) | |
640 | (describe "when the specified functions are whitelisted" | |
641 | (before-each | |
642 | (setq ido-cr+-function-whitelist | |
643 | (append '(whitelisted-command | |
644 | whitelisted-function | |
645 | whitelisted-collection) | |
646 | ido-cr+-function-whitelist))) | |
647 | (it "should enable ido in a whitelisted command" | |
648 | (expect | |
649 | (with-simulated-input "g RET" | |
650 | (call-interactively 'whitelisted-command)) | |
651 | :to-equal "green")) | |
652 | (it "should enable ido in a whitelisted function" | |
653 | (expect | |
654 | (with-simulated-input "g RET" | |
655 | (call-interactively 'cmd-that-calls-whitelisted-function)) | |
656 | :to-equal "green")) | |
657 | (it "should enable ido for a whitelisted collection" | |
658 | (expect | |
659 | (with-simulated-input "g RET" | |
660 | (ido-completing-read+ "Prompt: " 'whitelisted-collection)) | |
661 | :to-equal "green"))) | |
662 | (describe "when the whitelist is active but empty (i.e. nothing whitelisted)" | |
663 | (before-each | |
664 | (setq ido-cr+-function-whitelist (list nil))) | |
665 | (it "should prevent ido in a command" | |
666 | (expect | |
667 | (with-simulated-input "g RET" | |
668 | (call-interactively 'whitelisted-command)) | |
669 | :to-equal "g")) | |
670 | (it "should prevent ido in a function" | |
671 | (expect | |
672 | (with-simulated-input "g RET" | |
673 | (call-interactively 'cmd-that-calls-whitelisted-function)) | |
674 | :to-equal "g")) | |
675 | (it "should prevent ido for a collection" | |
676 | (expect | |
677 | (with-simulated-input "g RET" | |
678 | (ido-completing-read+ "Prompt: " 'whitelisted-collection)) | |
679 | :to-equal "g")))) | |
680 | ||
681 | (describe "with `ido-cr+-nil-def-alternate-behavior-list'" | |
682 | (before-all | |
683 | (setf (symbol-function 'def-nil-command) | |
684 | (lambda (arg) | |
685 | (interactive | |
686 | (list | |
687 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t))) | |
688 | arg) | |
689 | (symbol-function 'def-nil-function) | |
690 | (lambda () | |
691 | (completing-read "Prompt: " '("blue" "yellow" "green") nil t)) | |
692 | (symbol-function 'cmd-that-calls-def-nil-function) | |
693 | (lambda () | |
694 | (interactive) | |
695 | (funcall 'def-nil-function)) | |
696 | (symbol-function 'def-nil-collection) | |
697 | (lambda (string pred action) | |
698 | (complete-with-action action '("blue" "yellow" "green") string pred)))) | |
699 | (after-all | |
700 | (setf (symbol-function 'def-nil-command) nil | |
701 | (symbol-function 'def-nil-function) nil | |
702 | (symbol-function 'cmd-that-calls-def-nil-function) nil | |
703 | (symbol-function 'def-nil-collection) nil)) | |
704 | ||
705 | (describe "when the specified functions are not in the list" | |
706 | (before-each | |
707 | (setq ido-cr+-nil-def-alternate-behavior-list nil)) | |
708 | ||
709 | (it "should use empty string default in a command" | |
710 | (expect | |
711 | (with-simulated-input "RET" | |
712 | (call-interactively 'def-nil-command)) | |
713 | :to-equal "")) | |
714 | (it "should use empty string default in a function" | |
715 | (expect | |
716 | (with-simulated-input "RET" | |
717 | (call-interactively 'cmd-that-calls-def-nil-function)) | |
718 | :to-equal "")) | |
719 | (it "should use empty string default for a collection" | |
720 | (expect | |
721 | (with-simulated-input "RET" | |
722 | (ido-completing-read+ "Prompt: " 'def-nil-collection nil t)) | |
723 | :to-equal ""))) | |
724 | ||
725 | (describe "when the specified functions are in the list" | |
726 | (before-each | |
727 | (setq ido-cr+-nil-def-alternate-behavior-list | |
728 | (append '(def-nil-command | |
729 | def-nil-function | |
730 | def-nil-collection) | |
731 | ido-cr+-nil-def-alternate-behavior-list))) | |
732 | (it "should not use empty string default in a command" | |
733 | (expect | |
734 | (with-simulated-input "RET" | |
735 | (call-interactively 'def-nil-command)) | |
736 | :to-equal "blue")) | |
737 | (it "should not use empty string default in a function" | |
738 | (expect | |
739 | (with-simulated-input "RET" | |
740 | (call-interactively 'cmd-that-calls-def-nil-function)) | |
741 | :to-equal "blue")) | |
742 | (it "should not use empty string default for a collection" | |
743 | (expect | |
744 | (with-simulated-input "RET" | |
745 | (ido-completing-read+ "Prompt: " 'def-nil-collection nil t)) | |
746 | :to-equal "blue")))))) | |
747 | ||
748 | ;; (defun ido-cr+-run-all-tests () | |
749 | ;; (interactive) | |
750 | ;; (ert "^ido-cr\\+-")) | |
751 | ||
752 | ;;; test-ido-completing-read+.el ends here |