[comp.emacs] Need read-number function

reingold@m.cs.uiuc.edu (02/08/90)

I need a function read-number that would behave like (interactive "n");
that is, it would keep trying until a numeric value was typed.

Any suggestions?

eliot@phoenix.Princeton.EDU (Eliot Handelman) (02/08/90)

In article <4300068@m.cs.uiuc.edu> reingold@m.cs.uiuc.edu writes:
;
;I need a function read-number that would behave like (interactive "n");
;that is, it would keep trying until a numeric value was typed.
;
;Any suggestions?

How's about this:

(defun read-number (number)
   (interactive "nNumber: ")
   number)

kjones@talos.uu.net (Kyle Jones) (02/08/90)

reingold@m.cs.uiuc.edu writes:
 > I need a function read-number that would behave like (interactive "n");
 > that is, it would keep trying until a numeric value was typed.

[ Assuming GNU emacs here... ]

Yah, I had to code this one myself.  I don't know if a function like
this should be standard in the distribution or not.  Common Lisp's
elephantiasis is largely due to adopting functions from everyone's
toolbox.

Anyway, here's the function.

(defun read-number (prompt &optional initial-input)
  "Read a number from the minibuffer prompting with PROMPT.
If non-nil, the optional second argument INITIAL-INPUT should be a string
to insert into the minibuffer before reading."
  (let (result)
    (while (null result)
      (setq result (read-string prompt initial-input))
      (if (string-match "^ *-?[0-9]+" result)
	  (setq result (string-to-int result))
	(setq result nil)))
    result ))

jr@bbn.com (John Robinson) (02/08/90)

In article <4300068@m.cs.uiuc.edu>, reingold@m.cs writes:
>
>I need a function read-number that would behave like (interactive "n");
>that is, it would keep trying until a numeric value was typed.

In article <1990Feb8.132524.1694@talos.uu.net>, kjones@talos (Kyle Jones) writes:
>Yah, I had to code this one myself.  I don't know if a function like
>this should be standard in the distribution or not.  Common Lisp's
>elephantiasis is largely due to adopting functions from everyone's
>toolbox.

[defun omited].  It occurred to me that you could generalize Kyle's
function into somthing like:

  (read-thing prompt checker-function &optional initial-contents)

which asks for a lisp object until it gets one with the right type, as
passed by the checker-function.  Maybe ought to be a macro, or should
accept symbols like 'integer, 'string instead of a function name and
dispatch on them.

In article <13690@phoenix.Princeton.EDU>, eliot@phoenix (Eliot Handelman) writes:
>How's about this:
>
>(defun read-number (number)
>   (interactive "nNumber: ")
>   number)

Yeah, my initial reaction too.  This requires the additional
observation that, to call it from inside lisp code, you need to say:

  (call-interactively 'read-number)

... and there is no easy way to pass it a prompt at run time.  For
that, you would probably want to replace the defined function in the
call-interactively with a lambda-expression, but I'm not sure it is
possible to get the (interactive) part right if you do.  Or (ugh)
evaluate the defun inside the caller...
--
/jr, nee John Robinson     Life did not take over the globe by combat,
jr@bbn.com or bbn!jr          but by networking -- Lynn Margulis

ange@hplb.hpl.hp.com (Andy Norman) (02/09/90)

>>>>> On 8 Feb 90 01:40:30 GMT, reingold@m.cs.uiuc.edu said:

ed> I need a function read-number that would behave like (interactive "n");
ed> that is, it would keep trying until a numeric value was typed.

Well, this is absolutely disgusting, but it might do what you want:

(defun read-number (&optional prompt)
  (call-interactively (list 'lambda
			    '(num)
			    (list 'interactive
				  (concat "n" prompt))
			    'num)))

If you don't want a prompt, it becomes much easier:

(defun read-number ()
  (call-interactively '(lambda (num) (interactive "n") num)))

Hope this helps...
--
					-- ange --

					ange@hplb.hpl.hp.com

reingold@m.cs.uiuc.edu (02/09/90)

Here is the best suggestion I received (from Dale Worley):

(defun read-integer (prompt)
  "Read an integer from the minibuffer, prompting with PROMPT."
  (let ((value))
    (while (not (integerp value))
      (setq value (read-minibuffer prompt)))
    value))

merlyn@iwarp.intel.com (Randal Schwartz) (02/09/90)

In article <1990Feb8.132524.1694@talos.uu.net>, kjones@talos (Kyle Jones) writes:
|  > I need a function read-number that would behave like (interactive "n");
|  > that is, it would keep trying until a numeric value was typed.
| [ Assuming GNU emacs here... ]
| Yah, I had to code this one myself.  I don't know if a function like
| this should be standard in the distribution or not.  Common Lisp's
| elephantiasis is largely due to adopting functions from everyone's
| toolbox.
[code deleted]

why not just:

(defun rls-read-number ()
  "read a number from the keyboard"
  (call-interactively
   (function (lambda (arg) (interactive "n") arg))))

Okay, so, it's cheating. :-)

Just another GNU emacs hacker,
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

merlyn@iwarp.intel.com (Randal Schwartz) (02/09/90)

In article <51906@bbn.COM>, jr@bbn (John Robinson) writes:
| ... and there is no easy way to pass it a prompt at run time.  For
| that, you would probably want to replace the defined function in the
| call-interactively with a lambda-expression, but I'm not sure it is
| possible to get the (interactive) part right if you do.  Or (ugh)
| evaluate the defun inside the caller...

Ooops.  I should read *all* my news before posting.  Anyway,
to get a prompt into the thing, try:

(defun rls-read-number (prompt)
  "read a number from the keyboard, with PROMPT for a prompt"
  (call-interactively
   (list 'lambda
	 '(arg)
	 (list 'interactive
	       (concat "n" prompt))
	 'arg)))

It seems to work for me.  But, I only tested it once! :-)

Just another GNU Emacs hacker,
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

reingold@m.cs.uiuc.edu (02/10/90)

Here's the way I've written the general form.  Now that I've got it, I
can't figure out how I managed without it!

(defun read-object (prompt acceptable &optional initial-contents)
  "Return an object read from the minibuffer.
Prompt with the string PROMPT and use the function ACCEPTABLE to decide if
entered item is acceptable.  If non-nil, optional third arg INITIAL-CONTENTS
is a string to insert in the minibuffer before reading."
  (let ((value (read-minibuffer prompt initial-contents)))
    (while (not (funcall acceptable value))
      (setq value (read-minibuffer prompt initial-contents)))
    value))


For example, to read a month, defaulting to current-month, use

    (read-object
      "Enter month (1-12): "
      '(lambda (x) (and (integerp x) (<= 1 x) (<= x 12)))
      (int-to-string current-month))