(texinfo-section-types-regexp): Define here.
[bpt/emacs.git] / lisp / map-ynp.el
CommitLineData
6594deb0
ER
1;;; map-ynp.el --- General-purpose boolean question-asker.
2
eea8d4ef
ER
3;;; Copyright (C) 1991, 1992 Free Software Foundation, Inc.
4
e5167999 5;; Author: Roland McGrath <roland@gnu.ai.mit.edu>
fd7fa35a 6;; Keywords: lisp, extensions
e5167999 7
60205e0b
RM
8;;; This program is free software; you can redistribute it and/or modify
9;;; it under the terms of the GNU General Public License as published by
e5167999 10;;; the Free Software Foundation; either version 2, or (at your option)
60205e0b
RM
11;;; any later version.
12;;;
13;;; This program is distributed in the hope that it will be useful,
14;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; A copy of the GNU General Public License can be obtained from this
19;;; program's author (send electronic mail to roland@ai.mit.edu) or from
20;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
21;;; 02139, USA.
e5167999
ER
22
23;;; Commentary:
24
60205e0b
RM
25;;; map-y-or-n-p is a general-purpose question-asking function.
26;;; It asks a series of y/n questions (a la y-or-n-p), and decides to
27;;; applies an action to each element of a list based on the answer.
28;;; The nice thing is that you also get some other possible answers
29;;; to use, reminiscent of query-replace: ! to answer y to all remaining
30;;; questions; ESC or q to answer n to all remaining questions; . to answer
31;;; y once and then n for the remainder; and you can get help with C-h.
32
e5167999
ER
33;;; Code:
34
60205e0b 35;;;###autoload
907482b9 36(defun map-y-or-n-p (prompter actor list &optional help action-alist)
60205e0b 37 "Ask a series of boolean questions.
907482b9 38Takes args PROMPTER ACTOR LIST, and optional args HELP and ACTION-ALIST.
60205e0b
RM
39
40LIST is a list of objects, or a function of no arguments to return the next
41object or nil.
42
9fd54390 43If PROMPTER is a string, the prompt is \(format PROMPTER OBJECT\). If not
03759fe0
RM
44a string, PROMPTER is a function of one arg (an object from LIST), which
45returns a string to be used as the prompt for that object. If the return
46value is not a string, it is eval'd to get the answer; it may be nil to
47ignore the object, t to act on the object without asking the user, or a
48form to do a more complex prompt.
49
60205e0b
RM
50ACTOR is a function of one arg (an object from LIST),
51which gets called with each object that the user answers `yes' for.
52
53If HELP is given, it is a list (OBJECT OBJECTS ACTION),
54where OBJECT is a string giving the singular noun for an elt of LIST;
55OBJECTS is the plural noun for elts of LIST, and ACTION is a transitive
56verb describing ACTOR. The default is \(\"object\" \"objects\" \"act on\"\).
57
58At the prompts, the user may enter y, Y, or SPC to act on that object;
59n, N, or DEL to skip that object; ! to act on all following objects;
60ESC or q to exit (skip all following objects); . (period) to act on the
61current object and then exit; or \\[help-command] to get help.
62
907482b9
RM
63If ACTION-ALIST is given, it is an alist (KEY FUNCTION HELP) of extra keys
64that will be accepted. KEY is a character; FUNCTION is a function of one
65arg (an object from LIST); HELP is a string. When the user hits KEY,
66FUNCTION is called. If it returns non-nil, the object is considered
67\"acted upon\", and the next object from LIST is processed. If it returns
68nil, the prompt is repeated for the same object.
69
0a2eb25e
RS
70This function uses `query-replace-map' to define the standard responses,
71but not all of the responses which `query-replace' understands
72are meaningful here.
73
60205e0b 74Returns the number of actions taken."
0a2eb25e 75 (let* ((user-keys (if action-alist
08a6ff81
RM
76 (concat (mapconcat (function
77 (lambda (elt)
78 (key-description
79 (char-to-string (car elt)))))
907482b9
RM
80 action-alist ", ")
81 " ")
82 ""))
03329370
RM
83 ;; Make a map that defines each user key as a vector containing
84 ;; its definition.
0a2eb25e 85 (map (cons 'keymap
03329370
RM
86 (append (mapcar (lambda (elt)
87 (cons (car elt) (vector (nth 1 elt))))
0a2eb25e
RS
88 action-alist)
89 query-replace-map)))
aa228418 90 (actions 0)
0a2eb25e 91 prompt char elt tail def
aa228418
JB
92 (next (if (or (symbolp list)
93 (subrp list)
dbc4e1c1 94 (byte-code-function-p list)
aa228418
JB
95 (and (consp list)
96 (eq (car list) 'lambda)))
97 (function (lambda ()
98 (setq elt (funcall list))))
99 (function (lambda ()
100 (if list
101 (progn
102 (setq elt (car list)
103 list (cdr list))
104 t)
105 nil))))))
0a2eb25e 106
60205e0b
RM
107 (if (stringp prompter)
108 (setq prompter (` (lambda (object)
109 (format (, prompter) object)))))
ef0ba3e3 110 (while (funcall next)
60205e0b
RM
111 (setq prompt (funcall prompter elt))
112 (if (stringp prompt)
113 (progn
81eb8fcd 114 (setq quit-flag nil)
60205e0b
RM
115 ;; Prompt the user about this object.
116 (let ((cursor-in-echo-area t))
1586b965 117 (message "%s(y, n, !, ., q, %sor %s) "
907482b9
RM
118 prompt user-keys
119 (key-description (char-to-string help-char)))
0a2eb25e 120 (setq char (read-event)))
31ba9d39
RS
121 ;; Show the answer to the question.
122 (message "%s(y, n, !, ., q, %sor %s) %s"
123 prompt user-keys
124 (key-description (char-to-string help-char))
125 (single-key-description char))
0a2eb25e
RS
126 (setq def (lookup-key map (vector char)))
127 (cond ((eq def 'exit)
60205e0b 128 (setq next (function (lambda () nil))))
0a2eb25e 129 ((eq def 'act)
60205e0b 130 ;; Act on the object.
0a2eb25e 131 (funcall actor elt)
60205e0b 132 (setq actions (1+ actions)))
0a2eb25e 133 ((eq def 'skip)
60205e0b
RM
134 ;; Skip the object.
135 )
0a2eb25e 136 ((eq def 'act-and-exit)
60205e0b
RM
137 ;; Act on the object and then exit.
138 (funcall actor elt)
139 (setq actions (1+ actions)
140 next (function (lambda () nil))))
81eb8fcd
RS
141 ((eq def 'quit)
142 (setq quit-flag t)
143 (setq next (` (lambda ()
144 (setq next '(, next))
145 '(, elt)))))
0a2eb25e 146 ((eq def 'automatic)
0af46a8b
RM
147 ;; Act on this and all following objects.
148 (if (eval (funcall prompter elt))
149 (progn
150 (funcall actor elt)
151 (setq actions (1+ actions))))
aa228418 152 (while (funcall next)
0af46a8b 153 (if (eval (funcall prompter elt))
60205e0b
RM
154 (progn
155 (funcall actor elt)
bed40c39 156 (setq actions (1+ actions))))))
0a2eb25e
RS
157 ((eq def 'help)
158 (with-output-to-temp-buffer "*Help*"
159 (princ
160 (let ((object (if help (nth 0 help) "object"))
161 (objects (if help (nth 1 help) "objects"))
162 (action (if help (nth 2 help) "act on")))
163 (concat (format "Type SPC or `y' to %s the current %s;
164DEL or `n' to skip the current %s;
165! to %s all remaining %s;
166ESC or `q' to exit;\n"
167 action object object action objects)
168 (mapconcat (function
169 (lambda (elt)
170 (format "%c to %s"
171 (nth 0 elt)
172 (nth 2 elt))))
173 action-alist
174 ";\n")
175 (if action-alist ";\n")
176 (format "or . (period) to %s \
177the current %s and exit."
178 action object)))))
179
0af46a8b
RM
180 (setq next (` (lambda ()
181 (setq next '(, next))
182 '(, elt)))))
03329370 183 ((vectorp def)
907482b9 184 ;; A user-defined key.
03329370 185 (if (funcall (aref def 0) elt) ;Call its function.
907482b9
RM
186 ;; The function has eaten this object.
187 (setq actions (1+ actions))
188 ;; Regurgitated; try again.
189 (setq next (` (lambda ()
0a2eb25e
RS
190 (setq next '(, next))
191 '(, elt))))))
60205e0b
RM
192 (t
193 ;; Random char.
194 (message "Type %s for help."
195 (key-description (char-to-string help-char)))
196 (beep)
197 (sit-for 1)
0af46a8b
RM
198 (setq next (` (lambda ()
199 (setq next '(, next))
200 '(, elt)))))))
60205e0b
RM
201 (if (eval prompt)
202 (progn
0af46a8b
RM
203 (funcall actor elt)
204 (setq actions (1+ actions))))))
60205e0b
RM
205 ;; Clear the last prompt from the minibuffer.
206 (message "")
207 ;; Return the number of actions that were taken.
208 actions))
6594deb0
ER
209
210;;; map-ynp.el ends here