unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* completing-read enhancement
@ 2009-08-11  3:01 Paul Landes
  2009-08-11 15:12 ` Stefan Monnier
  0 siblings, 1 reply; 8+ messages in thread
From: Paul Landes @ 2009-08-11  3:01 UTC (permalink / raw)
  To: emacs-devel

This isn't a patch to completing-read, instead it is a new function.  I think
of it more as a facade with bells and whistles.  In summary, it makes prompting
for user input easy requiring terse, in the context of a function invocation,
code for this purpose.

(defun read-completing-choice (prompt choices &optional return-as-string
				      require-match initial-contents
				      history default allow-empty-p
				      no-initial-contents-on-singleton-p
				      add-prompt-default-p)
  "Read from the user a choice.

See `completing-read'.

PROMPT is a string to prompt with; normally it ends in a colon and a space.

CHOICES the list of things to auto-complete and allow the user to choose
  from.  Each element is analyzed independently If each element is not a
  string, it is written with `prin1-to-string'.

RETURN-AS-STRING is non-nil, return the symbol as a string
  (i.e. `symbol-name).

If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless
  the input is (or completes to) an element of TABLE or is null.
  If it is also not t, Return does not exit if it does non-null completion.

If INITIAL-CONTENTS is non-nil, insert it in the minibuffer initially.
  If it is (STRING . POSITION), the initial input
  is STRING, but point is placed POSITION characters into the string.

HISTORY, if non-nil, specifies a history list
  and optionally the initial position in the list.
  It can be a symbol, which is the history list variable to use,
  or it can be a cons cell (HISTVAR . HISTPOS).
  In that case, HISTVAR is the history list variable to use,
  and HISTPOS is the initial position (the position in the list
  which INITIAL-CONTENTS corresponds to).
  If HISTORY is `t', no history will be recorded.
  Positions are counted starting from 1 at the beginning of the list.

DEFAULT, if non-nil, will be returned when the user enters an empty
  string.

ALLOW-EMPTY-P, if non-nil, allow no data (empty string) to be returned.  In
  this case, nil is returned, otherwise, an error is raised.

NO-INITIAL-CONTENTS-ON-SINGLETON-P, if non-nil, don't populate with initialial
  contents when there is only one choice to pick from.

ADD-PROMPT-DEFAULT-P, if non-nil, munge the prompt using the default notation
  \(i.e. `<Prompt> (default CHOICE)')."
  (let* ((choice-alist-p (listp (car choices)))
	 (choice-options (if choice-alist-p (mapcar #'car choices) choices))
	 (sym-list (mapcar #'(lambda (arg)
			       (list
				(typecase arg
				  (string arg)
				  (t (prin1-to-string arg))
				  )))
			   choice-options))
	 (initial (if initial-contents
		      (if (symbolp initial-contents)
			  (symbol-name initial-contents)
			initial-contents)))
	 (def (if default
		  (typecase default
		    (nil nil)
		    (symbol default (symbol-name default))
		    (string default)
		    )))
	 res-str)
    (when (not no-initial-contents-on-singleton-p)
      (if (and (null initial) (= 1 (length sym-list)))
	  (setq initial (car (car sym-list))))
      (let (tc)
	(if (and (null initial)
		 ;; cases where a default is given and the user can't then just
		 ;; press return; instead, the user has to clear the minibuffer
		 ;; contents first
		 (null def)
		 (setq tc (try-completion "" sym-list)))
	    (setq initial tc))))
    (if (and add-prompt-default-p def)
	(setq prompt
	      (concat prompt (format " (default %s): " def))))
    (block wh
      (while t
	(setq res-str (completing-read prompt sym-list nil
				       require-match initial
				       history def))
	(if (or allow-empty-p (> (length res-str) 0))
	    (return-from wh)
	  (ding)
	  (message (substitute-command-keys
		    "Input required or type `\\[keyboard-quit]' to quit"))
	  (sit-for 5))))
    (when (> (length res-str) 0)
      (if choice-alist-p
	  (let ((choices (if (symbolp (caar choices))
			     (mapcar #'(lambda (arg)
					 (cons (symbol-name (car arg))
					       (cdr arg)))
				     choices)
			   choices)))
	    (setq res-str (cdr (assoc res-str choices))))
	(setq res-str
	      (if return-as-string
		  res-str
		(intern res-str)))))
    res-str))





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

* Re: completing-read enhancement
  2009-08-11  3:01 completing-read enhancement Paul Landes
@ 2009-08-11 15:12 ` Stefan Monnier
  2009-08-12  1:57   ` Paul Landes
  0 siblings, 1 reply; 8+ messages in thread
From: Stefan Monnier @ 2009-08-11 15:12 UTC (permalink / raw)
  To: Paul Landes; +Cc: emacs-devel

> This isn't a patch to completing-read, instead it is a new function.
> I think of it more as a facade with bells and whistles.  In summary,
> it makes prompting for user input easy requiring terse, in the context
> of a function invocation, code for this purpose.

Could you describe how it relates to completing-read (i.e. how it
differs, mostly; both from the point of view of the user, and from the
point of view of the coder)?


        Stefan




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

* Re: completing-read enhancement
  2009-08-11 15:12 ` Stefan Monnier
@ 2009-08-12  1:57   ` Paul Landes
  2009-08-16  5:04     ` Stefan Monnier
  0 siblings, 1 reply; 8+ messages in thread
From: Paul Landes @ 2009-08-12  1:57 UTC (permalink / raw)
  To: emacs-devel

Stefan Monnier <monnier <at> IRO.UMontreal.CA> writes:

> > This isn't a patch to completing-read, instead it is a new function.
> > I think of it more as a facade with bells and whistles.  In summary,
> > it makes prompting for user input easy requiring terse, in the context
> > of a function invocation, code for this purpose.
> 
> Could you describe how it relates to completing-read (i.e. how it
> differs, mostly; both from the point of view of the user, and from the
> point of view of the coder)?

The read-completing-choice uses completing-read and doesn't intend to supplant
it.  To the developer, it offers a quicker way of prompting the user purely
based on a list of choices (either symbols or strings) and .

It adds the following features:
 - accepts either symbols or string as input and converts between type
   automatically

 - returns user input as either a symbol or string

 - when the size of the list is one, the initial input is the car of the list

 - renders default formatting (i.e. "File" -> "File (default subst.el): ")

 - optionally allows for empty data

To the user, it provides a quicker (for most cases) way to select from the list
of choices (i.e. by populating the initial data from the choices passed or by
adding a default).

--
Paul Landes







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

* Re: completing-read enhancement
  2009-08-12  1:57   ` Paul Landes
@ 2009-08-16  5:04     ` Stefan Monnier
  2009-08-16 21:16       ` Paul Landes
  0 siblings, 1 reply; 8+ messages in thread
From: Stefan Monnier @ 2009-08-16  5:04 UTC (permalink / raw)
  To: Paul Landes; +Cc: emacs-devel

>> > This isn't a patch to completing-read, instead it is a new function.
>> > I think of it more as a facade with bells and whistles.  In summary,
>> > it makes prompting for user input easy requiring terse, in the context
>> > of a function invocation, code for this purpose.
>> 
>> Could you describe how it relates to completing-read (i.e. how it
>> differs, mostly; both from the point of view of the user, and from the
>> point of view of the coder)?

> The read-completing-choice uses completing-read and doesn't intend to
> supplant it.

I understand, yes, that's fine.

> To the developer, it offers a quicker way of prompting the user purely
> based on a list of choices (either symbols or strings) and.

> It adds the following features:
>  - accepts either symbols or string as input and converts between type
>    automatically
>  - returns user input as either a symbol or string

When/why are these useful?

>  - when the size of the list is one, the initial input is the car of the list

As a convention in Emacs, we usually prefer to start with an empty input
(and rely on the "use default if the result is the empty string"), so
I don't think this is something we want to encourage.

>  - renders default formatting (i.e. "File" -> "File (default subst.el): ")

This is good.

>  - optionally allows for empty data

Could you say something more about this.  E.g. why you came up with it,
in which situations did you find it useful/needed, ...

> To the user, it provides a quicker (for most cases) way to select from
> the list of choices (i.e. by populating the initial data from the
> choices passed or by adding a default).

IIUC, the initial data is built by (try-completion "" choices), right?
It might make sense when require-match is set, but ho often does it
return something else than ""?

As for "adding default", I don't find in the code where/how this is done,
could you explain what you mean by that?

One problem with your function is that it has even more arguments than
completing-read (which already has too many).


        Stefan


PS: BTW, (try-completion "" choices) should also work just fine for the
singleton case.




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

* Re: completing-read enhancement
  2009-08-16  5:04     ` Stefan Monnier
@ 2009-08-16 21:16       ` Paul Landes
  2009-08-17 14:54         ` Stefan Monnier
  0 siblings, 1 reply; 8+ messages in thread
From: Paul Landes @ 2009-08-16 21:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier writes:
 > > To the developer, it offers a quicker way of prompting the user purely
 > > based on a list of choices (either symbols or strings) and.
 > 
 > > It adds the following features:
 > >  - accepts either symbols or string as input and converts between type
 > >    automatically
 > >  - returns user input as either a symbol or string
 > 
 > When/why are these useful?

For the former: anytime you want a discrete set of branches in a
function and don't want to convert using a lot of `intern' and
`symbol-name' calls.  You'd give a symbol list as the choices in the
interactive form and use a `case' on the decision.  This is just one
example and there many situations where the input is a list of symbols
rather than strings.  Similarly, there many cases where you want a
symbol output.

 > As a convention in Emacs, we usually prefer to start with an empty
 > input (and rely on the "use default if the result is the empty
 > string"), so I don't think this is something we want to encourage.

Is this a new convention?  Seems I've run across many functions that
allow it (including `completing-read').  What's the alternative to
when it's useful to start with text to edit rather than creating this
text from scratch?

This is tangential, but I've actually recently looked for a GNU Emacs
style guide but haven't found anything with the exception of the elisp
manual.  Is there one?  If so, I'd like to read up on this (and other
things concerning style).

 > >  - optionally allows for empty data
 > 
 > Could you say something more about this.  E.g. why you came up with it,
 > in which situations did you find it useful/needed, ...

Sure.  In any case where a valid choice is a `nil' and you want to
make that available by the least amount of effort by the user--namely
just hitting the RET key.  One example is when repeat input is
required and RET breaks out of the loop.  It's the "other" choice that
isn't valid in the constraints of the intended purpose of the input
and rather some indication in the change of flow.

 > > To the user, it provides a quicker (for most cases) way to select from
 > > the list of choices (i.e. by populating the initial data from the
 > > choices passed or by adding a default).
 > 
 > IIUC, the initial data is built by (try-completion "" choices), right?
 > It might make sense when require-match is set, but ho often does it
 > return something else than ""?

Now that I look at it, you're correct.  I seem to remember putting it
there to defend against cases where the initial-contents wasn't in the
list of the choices.  However, I've tested that case and it doesn't
help so it would make sense to take it out.

 > As for "adding default", I don't find in the code where/how this is done,
 > could you explain what you mean by that?

I meant adding the default parameter to the function.

 > One problem with your function is that it has even more arguments than
 > completing-read (which already has too many).

I agree, it has a lot of parameters that are passed to it, but no more
that are required than `completing-read'.  Only the first two are
required and most use cases won't require more than three or maybe
four.

 > PS: BTW, (try-completion "" choices) should also work just fine for the
 > singleton case.

I agree.  I could refactor the function to use this and make it
simpler.  It appears as that the entire `when' could use a little
looking at.  Please keep in mind that this function was written years
ago and has been incrementally maintained (by myself).  You're the
second pair of eyes on the code, and as expected, providing good
feedback to make it better.

Thanks.

-- 
Paul Landes
landes@mailc.net




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

* Re: completing-read enhancement
  2009-08-16 21:16       ` Paul Landes
@ 2009-08-17 14:54         ` Stefan Monnier
  2009-08-20  0:24           ` Paul Landes
  0 siblings, 1 reply; 8+ messages in thread
From: Stefan Monnier @ 2009-08-17 14:54 UTC (permalink / raw)
  To: landes; +Cc: emacs-devel

>> > To the developer, it offers a quicker way of prompting the user purely
>> > based on a list of choices (either symbols or strings) and.
>> > It adds the following features:
>> >  - accepts either symbols or string as input and converts between type
>> >    automatically
>> >  - returns user input as either a symbol or string
>> When/why are these useful?
> For the former: anytime you want a discrete set of branches in a
> function and don't want to convert using a lot of `intern' and
> `symbol-name' calls.

I figured this part ;-)
What I meant is: how often does this happen for you.
My impression is that it's not very frequent, but maybe you've seen
it at many different places.

>> As a convention in Emacs, we usually prefer to start with an empty
>> input (and rely on the "use default if the result is the empty
>> string"), so I don't think this is something we want to encourage.
> Is this a new convention?

No, not at all.  It dates back to the introduction of the `def' argument
to completing-read.

> Seems I've run across many functions that
> allow it (including `completing-read').

We definitely allow and support it because it is occasionally good.
But we generally discourage its use.

> What's the alternative to when it's useful to start with text to edit
> rather than creating this text from scratch?

Usually we provide the value in `def' and let the user hit M-n if she
wants to edit the default.

> This is tangential, but I've actually recently looked for a GNU Emacs
> style guide but haven't found anything with the exception of the elisp
> manual.  Is there one?  If so, I'd like to read up on this (and other
> things concerning style).

There is no such style guide that I know.  We have some coding
conventions in the Elisp manual, but it's about as far as it goes.
If someone wants to start adding a "UI style guide" section, we'd be
happy to install it.

>> As for "adding default", I don't find in the code where/how this is done,
>> could you explain what you mean by that?
> I meant adding the default parameter to the function.

I do not understand what you mean.

>> One problem with your function is that it has even more arguments than
>> completing-read (which already has too many).
> I agree, it has a lot of parameters that are passed to it, but no more
> that are required than `completing-read'.  Only the first two are
> required and most use cases won't require more than three or maybe
> four.

The problem is not the length of the compulsory parameters, but the
overall length.


        Stefan




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

* Re: completing-read enhancement
  2009-08-17 14:54         ` Stefan Monnier
@ 2009-08-20  0:24           ` Paul Landes
  2009-09-10  5:13             ` Paul Landes
  0 siblings, 1 reply; 8+ messages in thread
From: Paul Landes @ 2009-08-20  0:24 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier writes:
 > >> When/why are these useful?
 > > For the former: anytime you want a discrete set of branches in a
 > > function and don't want to convert using a lot of `intern' and
 > > `symbol-name' calls.
 > 
 > I figured this part ;-)
 > What I meant is: how often does this happen for you.
 > My impression is that it's not very frequent, but maybe you've seen
 > it at many different places.

I use it quite a bit as I do a lot of things with symbols instead of
strings.  I also use the default prompt enhancement and prefer the
user interface.

To be more specific in answering your question, I've used a lot in the
JDEE (Java development under emacs) in a large code base I'm
integrating into the project.

 > >> As a convention in Emacs, we usually prefer to start with an empty
 > >> input (and rely on the "use default if the result is the empty
 > >> string"), so I don't think this is something we want to encourage.
 > > Is this a new convention?
 > 
 > No, not at all.  It dates back to the introduction of the `def'
 > argument to completing-read.

Ah, OK.

 > > Seems I've run across many functions that allow it (including
 > > `completing-read').
 > 
 > We definitely allow and support it because it is occasionally good.
 > But we generally discourage its use.

It does seem the use cases for it are fewer than the use cases
starting with empty input.  I also am a big fan of default input and
prefer that when possible.

 > > What's the alternative to when it's useful to start with text to edit
 > > rather than creating this text from scratch?
 > 
 > Usually we provide the value in `def' and let the user hit M-n if she
 > wants to edit the default.

Good to know.  Is this in every function that gets input from the
minibuffer (or whatever the technical name is of the area, I forgot).

 > > This is tangential, but I've actually recently looked for a GNU
 > > Emacs style guide but haven't found anything with the exception
 > > of the elisp manual.  Is there one?  If so, I'd like to read up
 > > on this (and other things concerning style).
 > 
 > There is no such style guide that I know.  We have some coding
 > conventions in the Elisp manual, but it's about as far as it goes.
 > If someone wants to start adding a "UI style guide" section, we'd
 > be happy to install it.

I might start something on the side like what you have here to a
document for myself and the JDEE project.  Perhaps when I have some
weight to it, I'll submit it.

 > >> As for "adding default", I don't find in the code where/how this
 > >> is done, could you explain what you mean by that?
 > > I meant adding the default parameter to the function.
 > 
 > I do not understand what you mean.

It is the seventh argument to the function of discussion
(`read-completing-choice').

 > >> One problem with your function is that it has even more arguments than
 > >> completing-read (which already has too many).
 > > I agree, it has a lot of parameters that are passed to it, but no more
 > > that are required than `completing-read'.  Only the first two are
 > > required and most use cases won't require more than three or maybe
 > > four.
 > 
 > The problem is not the length of the compulsory parameters, but the
 > overall length.

Yes, I agree.  Would it make sense to use CL style arguments?
Something like:

(read-completing-choice "Class" choices
                        :default default-input
                        :add-prompt-p t)

This would mean modifying my own code, but it is something I could
write something to programatically fix.

-- 
Paul Landes
landes@mailc.net




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

* Re: completing-read enhancement
  2009-08-20  0:24           ` Paul Landes
@ 2009-09-10  5:13             ` Paul Landes
  0 siblings, 0 replies; 8+ messages in thread
From: Paul Landes @ 2009-09-10  5:13 UTC (permalink / raw)
  To: emacs-devel

Any further thoughts on this?

> Stefan Monnier writes:






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

end of thread, other threads:[~2009-09-10  5:13 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-11  3:01 completing-read enhancement Paul Landes
2009-08-11 15:12 ` Stefan Monnier
2009-08-12  1:57   ` Paul Landes
2009-08-16  5:04     ` Stefan Monnier
2009-08-16 21:16       ` Paul Landes
2009-08-17 14:54         ` Stefan Monnier
2009-08-20  0:24           ` Paul Landes
2009-09-10  5:13             ` Paul Landes

Code repositories for project(s) associated with this public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).