Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lisp read-from-minibuffer propels deep questions

267 views
Skip to first unread message

Xah Lee

unread,
Apr 2, 2012, 10:01:18 PM4/2/12
to
slightly frustrated with emacs lisp read-from-minibuffer.

Spent now about a hour on this.

what i want i simple, like this:

(read-from-minibuffer
(format "Directory (default %s):" default-directory) default-
directory )

prompt user to enter a dir, with default at current dir.

however, according to inline doc of read-from-minibuffer, the second
arg for default input is obsolete. Instead, you have to use the 6th
arg. Quote:

(read-from-minibuffer PROMPT &optional INITIAL-CONTENTS KEYMAP READ
HIST DEFAULT-VALUE INHERIT-INPUT-METHOD)

the doc is long so i won't paste here. See it by calling “describe-
function”.

Now, so i do:

(read-from-minibuffer
(format "Directory (default %s):" default-directory) nil nil nil nil
default-directory)

doesn't work. Read the doc again, it turns out that the 4th arg must
be t in order for the default value to work, else you get empty string
if the user just press Enter.

So i do

(read-from-minibuffer
(format "Directory (default %s):" default-directory) nil nil t nil
default-directory)

woops! no go! because if the 4th arg is t, it means the input as a
string will be fed to lisp reader, then interpreted as a lisp object.
Hot damn. This means, if you want a string, you have to feed it
「"\"mystring\""」. (the outter string makes it a lisp string to be fed
to lisp reader, then, the inner string gets you a lisp string object)

So, now i have to do this:

(read-from-minibuffer
(format "Directory (default %s):" default-directory) nil nil t nil
(format "\"%s\"" default-directory) )

But no! Because, now if user actually enter a value, e.g. type 「mary」,
lisp reader freaks out. Again, it doesn't undertand what the letter
sequence 「mary」 is. It wants a string 「"\"mary\""」. So, user will have
to actually type 「"mary"」 for this to work.

WTF?

This line is supposed to be done in 20 seconds. Now i've spent 40min
on this. Now, my mind wanders to the deep question of humanity….

Xah

Kevin Rodgers

unread,
Apr 3, 2012, 12:57:35 AM4/3/12
to help-gn...@gnu.org
On 4/2/12 8:01 PM, Xah Lee wrote:
> slightly frustrated with emacs lisp read-from-minibuffer.
>
> Spent now about a hour on this.
>
> what i want i simple, like this:
>
> (read-from-minibuffer
> (format "Directory (default %s):" default-directory) default-
> directory )
>
> prompt user to enter a dir, with default at current dir.
>
> however, according to inline doc of read-from-minibuffer, the second
> arg for default input is obsolete. Instead, you have to use the 6th
> arg. Quote:
>
> (read-from-minibuffer PROMPT&optional INITIAL-CONTENTS KEYMAP READ
The READ arg is not meant to work around the fact that read-from-minibuffer
returns an empty string if the user does not enter any text.

INITIAL-CONTENTS may be deprecated but it is not obsolete: it still works.

Here are 3 alternatives:

(read-from-minibuffer "Directory: " default-directory)

(let ((directory (read-from-minibuffer
(format "Directory (default %s): " default-directory)
nil nil nil nil default-directory)))
(if (equal directory "")
default-directory
directory))

(let ((insert-default-directory t))
(read-directory-name "Directory: " default-directory))


--
Kevin Rodgers
Denver, Colorado, USA


Drew Adams

unread,
Apr 3, 2012, 1:35:49 AM4/3/12
to Xah Lee, help-gn...@gnu.org
> (read-from-minibuffer
> (format "Directory (default %s):" default-directory)
> default-directory )
>
> prompt user to enter a dir, with default at current dir.

Try `read-directory-name'. (Its doc too is a bit confusing, IMO.) Here are a
couple ways to read the name of a directory. The first requires the input to be
an existing directory; the second does not.

(expand-file-name
(read-directory-name
(format "Directory (default %s): " default-directory)
default-directory default-directory t))

(let ((insert-default-directory t))
(read-directory-name "Directory: " default-directory))

You can also use `read-file-name'. Both of those functions let the user use
completion: they are file/dir-name aware.

`read-from-minibuffer' on the other hand just reads a string (and optionally
calls the Lisp reader on it).

> however, according to inline doc of read-from-minibuffer, the second
> arg for default input is obsolete.

(FWIW, I disagree with that pronouncement by Emacs Devel, but so be it.)

The doc actually says, at the very end, that you can use the second arg if the
HIST arg is a cons, i.e., is a non-nil history list.

Example:

(read-from-minibuffer "Directory: " default-directory
nil nil file-name-history)

or just (read-from-minibuffer "Directory: " default-directory) if you don't care
about using the file-name history (`M-p').

If you avoid using the "deprecated" INITIAL-CONTENTS arg (like a good boy), then
you must test the string input by the user, and if it is "" then return
DEFAULT-VALUE:

(let ((input (read-from-minibuffer
(format "Directory (default %s): " default-directory)
nil nil nil nil default-directory)))
(when (string= "" input) (setq input default-directory))
input)

But again, `read-from-minibuffer' does not know anything about file or dir names
or how to complete them (unless you jump through hoops, providing it a
file/dir-name completion keymap).

> Instead, you have to use the 6th arg.

Nope, as you discovered, nothing gets inserted in the minibuffer, and empty
input means "" is returned.

> Read the doc again, it turns out that the 4th arg must
> be t in order for the default value to work, else you get empty string
> if the user just press Enter.

Nope, as you discovered. That's something else again.

> woops! no go! because if the 4th arg is t, it means the input as a
> string will be fed to lisp reader, then interpreted as a lisp object.
> Hot damn. This means, if you want a string, you have to feed it
> ?"\"mystring\""?. (the outter string makes it a lisp string to be fed
> to lisp reader, then, the inner string gets you a lisp string object)

No, don't even think of going down that road.

`read-from-minibuffer' is a very general function, which is one reason its doc
is confusing (not that that is an excuse). It is used to implement
`completing-read', `read-file-name', and so on. The 4th arg is only for
situations where you want to get user input as a Lisp sexp and then evaluate it.

> But no! ... WTF?
> This line is supposed to be done in 20 seconds. Now i've spent 40min
> on this. Now, my mind wanders to the deep question of humanity..

Try using `read-file-name' or `read-directory-name'. They should help.


Xah Lee

unread,
Apr 3, 2012, 1:58:03 AM4/3/12
to
Thanks a lot to Kevin Rogers and Drew Adams, for the very informative
and quick help. Thanks guys.

Xah

Stefan Monnier

unread,
Apr 3, 2012, 9:06:27 PM4/3/12
to
> slightly frustrated with emacs lisp read-from-minibuffer.

Then don't use it. It's mostly an internal function used to implement
things like read-string, read-file-name, read-directory-name, ...


Stefan

Xah Lee

unread,
Apr 4, 2012, 12:24:59 AM4/4/12
to
i probably wouldn't have used it if i've read the elisp manual on
minibuffers.

Xah

Joe keane

unread,
Apr 12, 2012, 10:03:38 PM4/12/12
to
In article <jwvk41ws3v8.fsf-mon...@gnu.org>,
Stefan Monnier <mon...@iro.umontreal.ca> wrote:
>Then don't use it.

Because the parsing for 'interactive' works pretty well, for some 90% of
the cases.

If you are bored, check out "background.el". When in the prompt, keys
like C-b, C-f, C-a, C-e work fine default, only C-p, C-n, C-s, C-r need
to play games.
0 new messages