all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Canonical way to add a pre-filter to completing-read
@ 2018-05-10 13:09 Kaushal Modi
  2018-05-10 14:10 ` Drew Adams
  2018-05-10 15:21 ` Stefan Monnier
  0 siblings, 2 replies; 6+ messages in thread
From: Kaushal Modi @ 2018-05-10 13:09 UTC (permalink / raw)
  To: Help Gnu Emacs mailing list

Hello,

I want to use completing-read to provide a "pre-filter" to narrow down the
completion list.

My real use use is to take the symbol-at-point as the pre-filter to narrow
down in a list of all identifiers. For a real example, the symbol name is
"walkDirRec", but the completion list contains "os.walkDirRec".. so I am
trying to figure out how to use completing-read with that.

(I am aware that I can use the counsel library to make this easier, but was
looking for a way for completing-read to Just Work(TM).)

So here are some minimal examples to explain my conundrum..

Below works exactly as I want.. but the docs and manual say that
INITIAL-INPUT is deprecated.

(completing-read "Entry: " '("abc" "bcd" "cde") nil :require-match "bc")
;INITIAL-INPUT deprecated, but works as I want

Above will show in the completion list with just the filtered items
matching "bc":

    abc
    bcd

So following the manual, I tried using the DEF (default) argument instead,
but that doesn't work as I want.. that just throws in that DEF value
verbatim to the completion list..

(completing-read "Entry: " '("abc" "bcd" "cde") nil :require-match nil nil
"bc") ;Using DEF does not work.. it just inserts that as one more element
in the completion list

Above will end up with this list:

    bc
    abc
    bcd
    cde

So the DEF approach is not useful unless the DEF value is matching exactly
with one of the items in COLLECTION.

So, what would be the right way, i.e. not using the deprecated
INITIAL-INPUT?

Thanks.
-- 

Kaushal Modi


^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: Canonical way to add a pre-filter to completing-read
  2018-05-10 13:09 Canonical way to add a pre-filter to completing-read Kaushal Modi
@ 2018-05-10 14:10 ` Drew Adams
  2018-05-10 17:36   ` Kaushal Modi
  2018-05-10 15:21 ` Stefan Monnier
  1 sibling, 1 reply; 6+ messages in thread
From: Drew Adams @ 2018-05-10 14:10 UTC (permalink / raw)
  To: Kaushal Modi, Help Gnu Emacs mailing list

> I want to use completing-read to provide a "pre-filter" to
> narrow down the completion list.

Possibilities:

1. Filter the list of completions before passing it.
   IOW, pass '("abc" "bcd"), not '("abc" "bcd" "cde").
   (Or if COMPLETIONS is a function, have it also filter,
   as and when needed.)

2. Provide a PREDICATE arg that filters as needed.  E.g.,
   (lambda (xx) (string-match-p "bc" xx)).

With vanilla Emacs:

If you use a non-function COMPLETIONS arg then you need
to establish that list of candidates before completing.
You have only PREDICATE to play with.  The candidates
are determined independently of whatever input might be
in the minibuffer

If you use a function COMPLETIONS arg then the function
can take into account the current minibuffer input.
The function can do anything you want, to come up with
the (current, dynamically computed) set of candidates.

----

Wrt INITIAL-INPUT: It should not be considered deprecated.
There was never any need for that.  It should have been
enough for the manual or doc string to just explain the
difference between DEF and INITIAL-INPUT, and to suggest
that in many (most?) cases it can be more user-friendly
or more useful to use only DEF.  The "deprecation" of
this arg was uncalled for, IMHO.

----

If you use Icicles:

1. There are 3 possibilities for filtering with a predicate:

   a. Use argument PREDICATE.  As usual, it filters raw
      COMPLETIONS, e.g., alist elements or obarray symbols,
      and it does so before you type anything in the
      minibuffer.  Nothing new here.

   b. Bind variable `icicle-must-pass-after-match-predicate'
      around the `completing-read' call.  It filters the
      _displayed_ candidates (strings - what you see in
      `*Completions*'), and it does so _after_ matching your
      minibuffer input.

   c. Bind variable `icicle-must-pass-predicate': same as
      `icicle-must-pass-after-match-predicate', but before
      matching your current input.

   These can be used in combination.  PREDICATE filters all
   initial candidates, even when that might be wasteful (not
   so performant) because you've typed some text that would
   more quickly rule out many of them, if matched first.

   Different use cases call for different matching orders.
   Sometimes it makes sense to use only PREDICATE, filtering
   all raw candidates ahead of time.  Sometimes it makes
   sense to do input-matching first, before applying a
   given predicate.

2. Option `icicle-default-value' controls arg DEF: whether
   it is shown in the prompt, gets substituted for an empty
   INITIAL-INPUT, and so on.  In particular, 4 of the 6
   values insert the default value into the minibuffer:

   `insert-start'    - Insert DEF and leave cursor at start.
   `insert-end'      - Insert DEF and leave cursor at end.
   `preselect-start' - Insert & preselect DEF; cursor at start.
   `preselect-end'   - Insert & preselect DEF; cursor at end.

> Below works exactly as I want.. but the docs and manual
> say that INITIAL-INPUT is deprecated.
>
> (completing-read "Entry: " '("abc" "bcd" "cde") nil
>                  :require-match "bc")
>
> So, what would be the right way, i.e. not using the
> deprecated INITIAL-INPUT?

Ignore the docs.  Emacs was wrong to proclaim INITIAL-INPUT
deprecated.  It can be useful.  It never hurt anyone for
Emacs to make it available.  It is enough to suggest to
users that it is more conventional, and typically more
user-friendly, to use only DEF.

With luck, this silly uber-control will be removed from
the docs someday.  Don't be scared away from using it
when it suits your purpose.

(Just one opinion.)



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Canonical way to add a pre-filter to completing-read
  2018-05-10 13:09 Canonical way to add a pre-filter to completing-read Kaushal Modi
  2018-05-10 14:10 ` Drew Adams
@ 2018-05-10 15:21 ` Stefan Monnier
  2018-05-10 17:19   ` Kaushal Modi
  1 sibling, 1 reply; 6+ messages in thread
From: Stefan Monnier @ 2018-05-10 15:21 UTC (permalink / raw)
  To: help-gnu-emacs

> (completing-read "Entry: " '("abc" "bcd" "cde") nil :require-match "bc")
> ;INITIAL-INPUT deprecated, but works as I want
>
> Above will show in the completion list with just the filtered items
> matching "bc":
>
>     abc
>     bcd

Could you clarify exactly here:
- "will show"... when the user does what?
  Just calling the above `completing-read` won't show any list of completions
- When I hit ? at the prompt, I indeed get a list of completions, but
  that list only includes `bcd` because the default completion style
  does not include `substring`.  So your use/test case is different from
  the default.

Let's say the user does

    M-: (km-completion "Entry: " '("abc" "bcd" "cde") "bc") RET

and then types `a` (and then hits `?` to see the list of remaining
completions, or maybe he uses icomplete-mode to always see the list of
remaining candidates).  What do you want the list of completions to be
at that point?

Some things you can do with the standard completion-UI:
- setup your completion table such that it uses `substring` completion
  by default.
- use `completion-table-in-turn` with the first table being a sub-table
  which only includes the entries that match "bc".


-- Stefan




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Canonical way to add a pre-filter to completing-read
  2018-05-10 15:21 ` Stefan Monnier
@ 2018-05-10 17:19   ` Kaushal Modi
  2018-05-10 22:05     ` Stefan Monnier
  0 siblings, 1 reply; 6+ messages in thread
From: Kaushal Modi @ 2018-05-10 17:19 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

Hello,

On Thu, May 10, 2018 at 11:22 AM Stefan Monnier <monnier@iro.umontreal.ca>
wrote:

>
> Could you clarify exactly here:
> - "will show"... when the user does what?
>   Just calling the above `completing-read` won't show any list of
> completions
>

Hmm. I use the ivy package, that provides a vertical list selection
interface even when using completing-read. This is what I meant:
https://i.imgur.com/1Ki7uFX.gifv

In the GIF, I first set the "bc" value to INITIAL-INPUT. In the later part
of the GIF, I set it to DEF, where that "bc" simply gets added to the
available entries (and also of no use to me).

- When I hit ? at the prompt, I indeed get a list of completions, but
>   that list only includes `bcd` because the default completion style
>   does not include `substring`.  So your use/test case is different from
>   the default.
>

Is there a way to make it behave as you see in the first part of that GIF?
i.e. make the "bc" filter the available candidates?

Let's say the user does
>
>     M-: (km-completion "Entry: " '("abc" "bcd" "cde") "bc") RET
>
> and then types `a` (and then hits `?` to see the list of remaining
> completions, or maybe he uses icomplete-mode to always see the list of
> remaining candidates).  What do you want the list of completions to be
> at that point?
>

If I type `a` there, the entry would become "bca", and nothing will match..
but if I do `C-a a`, the entry will be "abc", and will show only that "abc"
element.


> Some things you can do with the standard completion-UI:
> - setup your completion table such that it uses `substring` completion
>   by default.
>

That sounds like that would work.. can you please point to an example?


> - use `completion-table-in-turn` with the first table being a sub-table
>   which only includes the entries that match "bc".
>

I did not understand this suggestion.

-- 

Kaushal Modi


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Canonical way to add a pre-filter to completing-read
  2018-05-10 14:10 ` Drew Adams
@ 2018-05-10 17:36   ` Kaushal Modi
  0 siblings, 0 replies; 6+ messages in thread
From: Kaushal Modi @ 2018-05-10 17:36 UTC (permalink / raw)
  To: Drew Adams; +Cc: Help Gnu Emacs mailing list

Hi Drew,

On Thu, May 10, 2018 at 10:10 AM Drew Adams <drew.adams@oracle.com> wrote:

> Possibilities:
>
> 1. Filter the list of completions before passing it.
>    IOW, pass '("abc" "bcd"), not '("abc" "bcd" "cde").
>    (Or if COMPLETIONS is a function, have it also filter,
>    as and when needed.)
>

Pre-filtering would not work in my case, as I might even need to change the
filter on the fly *after it got initially set using INITIAL-INPUT*. See how
I use it in this GIF (the same that I linked in my earlier reply to
Stefan): https://imgur.com/1Ki7uFX.

2. Provide a PREDICATE arg that filters as needed.  E.g.,
>    (lambda (xx) (string-match-p "bc" xx)).
>

That might.. work. I will have to try.

With vanilla Emacs:
>
> If you use a non-function COMPLETIONS arg then you need
> to establish that list of candidates before completing.
> You have only PREDICATE to play with.  The candidates
> are determined independently of whatever input might be
> in the minibuffer
>
> If you use a function COMPLETIONS arg then the function
> can take into account the current minibuffer input.
> The function can do anything you want, to come up with
>
> the (current, dynamically computed) set of candidates.


Let me play with PREDICATE. At the moment, the COMPLETIONS is just a list.
I will look into that if setting PREDICATE does not work.


> > Below works exactly as I want.. but the docs and manual
> > say that INITIAL-INPUT is deprecated.
> >
> > (completing-read "Entry: " '("abc" "bcd" "cde") nil
> >                  :require-match "bc")
> >
> > So, what would be the right way, i.e. not using the
> > deprecated INITIAL-INPUT?
>
> Ignore the docs.  Emacs was wrong to proclaim INITIAL-INPUT
> deprecated.  It can be useful.  It never hurt anyone for
> Emacs to make it available.  It is enough to suggest to
> users that it is more conventional, and typically more
> user-friendly, to use only DEF.
>
> With luck, this silly uber-control will be removed from
> the docs someday.  Don't be scared away from using it
> when it suits your purpose.
>

For now, I am using the INITIAL-INPUT as that solves the purpose. But I
will later try out the PREDICATE.


> (Just one opinion.)
>

Thanks for that :)
-- 

Kaushal Modi


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Canonical way to add a pre-filter to completing-read
  2018-05-10 17:19   ` Kaushal Modi
@ 2018-05-10 22:05     ` Stefan Monnier
  0 siblings, 0 replies; 6+ messages in thread
From: Stefan Monnier @ 2018-05-10 22:05 UTC (permalink / raw)
  To: Kaushal Modi; +Cc: help-gnu-emacs

>>     M-: (km-completion "Entry: " '("abc" "bcd" "cde") "bc") RET
>> and then types `a` (and then hits `?` to see the list of remaining
>> completions, or maybe he uses icomplete-mode to always see the list of
>> remaining candidates).  What do you want the list of completions to be
>> at that point?
> If I type `a` there, the entry would become "bca",

Is "bca" really what you think would be ideal here (where the user
never typed "bc")?

That seems to imply the user would have to use something like C-a C-k in
order to type something completely different from "bc".  Most UIs seem
to find such behavior undesirable, AFAIK (in the default Emacs UI we
shun initial inputs altogether, requiring the user to hit M-n if he
wants to edit the default; and in more "mainstream" UIs I know, the
initial input is highlighted/selected at first, and hitting "a" would
first delete it (you'd need to use a cursor key first in order to
de-select the text before hitting "a" in order to keep the "bc")).

>> Some things you can do with the standard completion-UI:
>> - setup your completion table such that it uses `substring` completion
>>   by default.
> That sounds like that would work.. can you please point to an example?

You want to setup your completion table so it returns a `metadata` which
includes a `category` of your choice, and then you want to add an entry
for that category to completion-category-defaults.

This is done for example for read-char-by-name.

>> - use `completion-table-in-turn` with the first table being a sub-table
>>   which only includes the entries that match "bc".
> I did not understand this suggestion.

You could setup your completion table such that the UI would behave as
follows:

- Imagine your list of completion candidates is abc, bcd, acd, cde.
- And you want to start by filtering for "bc".
- At first the minibuffer says "Entry: "
- At this point the available completions would be "abc" and "bcd".
- Then the user hits "a".
- The minibuffer becomes "Entry: a"
- The available completions become just "abc" and nothing else.
- Then the user hits "ac".
- The minibuffer becomes "Entry: ac"
- The available completions become just "acd" and nothing else.

You'd do this by combining (with the mentioned function) two completion
tables: one containing only the entries that match "bc" and the other
containing all the entries, so when the input matches in the first
table, we stay in the first stable, but if it doesn't, then we search in
the second table.


        Stefan



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-05-10 22:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-05-10 13:09 Canonical way to add a pre-filter to completing-read Kaushal Modi
2018-05-10 14:10 ` Drew Adams
2018-05-10 17:36   ` Kaushal Modi
2018-05-10 15:21 ` Stefan Monnier
2018-05-10 17:19   ` Kaushal Modi
2018-05-10 22:05     ` Stefan Monnier

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.