Open jkitchin opened 3 years ago
ivy doesn't seem to handle completing-read-multiple (or at least not the same as it does completing-read)
I guess that's because completing-read-multiple
can't be customised as easily as, say, completing-read
via completing-read-function
, and because there's less interest in completing-read-multiple
, or people who use it (like me) don't mind it's current behaviour.
I feel like I should be able to mark candidates and press RET, and use keys like C-M-m/n/p to select them with RET to select them, and no TAB required.
I don't think you can get those perks without rewriting (or emulating) completing-read-multiple
in terms of ivy-read
(that's the whole premise of the Counsel library).
Anyway, I wondered if I am missing something in ivy that would make these feasible?
Marking and non-exiting completion are already possible, but AFAIK only via the ivy-read
API. I recall counsel-org-tag
or one of those commands using that kind of UI, for example.
Is that something that would be interesting?
I don't see why not :). Bonus points for submitting an upstream feature request or patch via report-emacs-bug
to make completing-read-multiple
more tweakable by packages ;). Thanks.
vertico and selectrum seem to have completing-read-multiple support. would be nice if ivy had too :-)
I feel I have changed my thinking on the need for ivy to support completing-read-multiple. Since I opened this issue, I have tried using completing-read-multiple, and it is awkward to me compared to being able to mark entries (now supported in ivy) and act on the list.
For example, you can run this:
(ivy-read "t: " '(a b c d)
:multi-action (lambda (x) (insert (string-join x ",")))
:action (lambda (x) (insert x)))
Type C-o and then use m to mark some entries. When you press Return, it will insert a comma delimited list of the marked entries, and if you don't mark any the selected entry.
You also have non-exiting completion as @basil-conto noted, so that is another route to the same end. With these options, completing-multiple-read seems deprecated.
I don't mind if we close this issue.
You also have non-exiting completion as @basil-conto noted, so that is another route to the same end. With these options, completing-multiple-read seems deprecated.
FWIW we came to the same conclusion in the context of the alternative completion packages Vertico and Embark. Embark also offers a non-exiting embark-act-all
command which makes CRM obsolete. Furthermore CRM is not used very much in Emacs or the ecosystem. It seems like a dead end.
While completing-read-multiple might not be used much, org-set-tags-command
uses it to this day and it is very much not deprecated despite the lack of popularity. Although it might not be worth it to offer it as a choice over ivy-mark
, it is still worth it to provide a wrapper.
(defun k/ivy-completing-read-multiple (prompt collection
&optional
predicate require-match initial-input
history def inherit-input-method)
"A drop-in replacement of `completing-read-multiple' utilizing `ivy-mark'.
PROMPT, COLLECTION, PREDICATE, REQUIRE-MATCH, INITIAL-INPUT,
HISTORY, DEF, and INHERIT-INPUT-METHOD are all forwarded to
`ivy-completing-read'; they are described by `completing-read'.
\\<ivy-minibuffer-map>\\[ivy-done] submits the marked entries; if
no entries are marked, this works the same as
`ivy-completing-read' except the entry is returned in a list for
consistency.
Use \\[ivy-mark] to mark items, \\[ivy-unmark] to unmark, and
\\[ivy-toggle-marks] to toggle all items."
(let ((answer
(ivy-completing-read
prompt collection predicate require-match
initial-input history def inherit-input-method)))
(or (->> ivy-marked-candidates
(--map (substring it (length ivy-mark-prefix)))
(--map (ivy--call-cand it)))
(and (not (equal "" answer))
(list answer)))))
A wrapper can be written that returns ivy-marked-candidates
(processed like how ivy--call-marked
does it) after a normal ivy-completing-read
is done if it is non-nil (some candidates are marked); if no candidates are marked, it can just return the value selected by ivy-completing-read
, wrapped in a list to be consistent with the original behavior.
There are two related questions in this issue:
For calls to completing-read, ivy does a beautiful job for selecting a candidate. I have not found a way to make it select multiple candidates though, and I wondered if this is just impossible. It does not work, for example to mark candidates and press return, and it does not work to use keys like C-M-m to select and continue.
Anyway, I wondered if I am missing something in ivy that would make these feasible?
Thanks,
EDIT:
I came up with a solution that uses a modified version of ivy-completing-read. The modifications include augmenting the keymap to make keys like C-M-m/n/p mark candidates instead of acting on them, and at the end if there is anything in ivy-marked-candidates return those candidates instead of a single string. This lets me get a string, or a list of strings from one call.
Now that it is done, I am not sure it is actually a good idea, because it is not a drop in replacement for completing-read since it can return a string, or a list of strings (which surely would break a lot of code after the completing-read call).
However, it does look like an easy way to extend ivy support to
completing-read-multiple
. Is that something that would be interesting?