1 ;;; doremi.el --- Do Re Mi: Incremental change using arrow keys or mouse wheel.
4 ;; Description: Incremental change using arrow keys or mouse wheel.
6 ;; Maintainer: Drew Adams
7 ;; Copyright (C) 2004-2011, Drew Adams, all rights reserved.
8 ;; Created: Thu Sep 02 08:21:37 2004
10 ;; Last-Updated: Wed Sep 7 15:53:07 2011 (-0700)
13 ;; URL: http://www.emacswiki.org/cgi-bin/wiki/doremi.el
14 ;; Keywords: keys, cycle, repeat, higher-order
15 ;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x
17 ;; Features that might be required by this library:
19 ;; `mwheel', `ring', `ring+'.
21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25 ;; Do Re Mi: Incremental change using arrow keys or mouse wheel.
27 ;; When you invoke Do Re Mi commands, you can then press and hold an
28 ;; up/down arrow key, or turn the mouse wheel, to run up and down the
29 ;; scale: do, re, mi,...
31 ;; Use the up/down arrow keys or the mouse wheel to:
33 ;; - Change nearly any parameter incrementally (dynamically).
35 ;; - Repeat an action.
37 ;; - Cycle through a set of values, without changing anything (for
38 ;; example, to choose an item). In this use, think of choosing
39 ;; from a menu. This is similar to using a minibuffer history.
40 ;; The input choices can take the form of any Emacs-Lisp sequence
41 ;; (list, array, string, vector) - this sequence is converted to a
42 ;; circular structure (ring).
44 ;; - Do just about anything: call a different function for each
47 ;; This works with numerical parameters that can be incremented and
48 ;; decremented, and it works with parameters that can take on one of a
49 ;; number of values. In fact, it is even more general than that: you
50 ;; can use it to associate nearly any function or pair of functions
51 ;; with the arrow keys and the mouse wheel.
53 ;; By default, the up and down arrow keys are used, but any other keys
54 ;; may be used instead. Mouse wheel movements are recognized for
55 ;; Emacs 20 and Emacs 21 (using library `mwheel.el'). `mouse-2'
56 ;; presses are ignored, so that they won't interfere with rotating the
59 ;; See the doc string for function `doremi' for more information.
61 ;; Code defining a few example commands is included here (but
62 ;; commented out), so you can see how to use this. For more examples
63 ;; of using function `doremi', see files `doremi-frm.el' and
66 ;; This library uses library `ring+.el', which provides extensions to
67 ;; the standard library `ring.el' to let you manipulate circular
71 ;; Non-interactive functions defined here:
73 ;; `doremi', `doremi-intersection', `doremi-limit',
74 ;; `doremi-set-new-value', `doremi-wrap'.
76 ;; User options (variables) defined here:
78 ;; `doremi-boost-down-keys', `doremi-boost-scale-factor',
79 ;; `doremi-boost-up-keys', `doremi-down-keys', `doremi-up-keys'.
81 ;; Add this to your initialization file (~/.emacs or ~/_emacs):
85 ;; See also these related libraries that make use of `doremi':
87 ;; `doremi-frm.el' - Incrementally adjust frame properties.
88 ;; `doremi-cmd.el' - Other Do Re Mi commands.
89 ;; `doremi-mac.el' - Macro to define Do Re Mi commands and
90 ;; automatically add them to Do Re Mi menu.
92 ;; This has been tested on GNU Emacs 20, 21, and 22 on MS Windows.
97 ;; - Replace `boost-*' keys by test for modifiers (as for wheel).
98 ;; - Combine with customize. That is, have customize buffers use
99 ;; Do Re Mi commands to defined numeric or enumeration values.
100 ;; - Provide buttons (menu items) in menus that act like up & down
103 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
108 ;; doremi: Use mouse-wheel-(up|down)-event everywhere. Thx to Michael Heerdegen.
110 ;; Removed autoload cookies from non-interactive functions.
111 ;; Added autoload cookies for defgroup, defcustom.
113 ;; doremi-wrap: Wrap value around, instead of just moving to the other limit.
115 ;; doremi: Increment can now be a list of numbers.
116 ;; Use >= 0, not natnump, since not necessarily an integer.
118 ;; Added: doremi-intersection.
119 ;; Renamed options doremi-...-key to doremi-...-keys, and made them lists.
120 ;; Added top-level warning when load the library if obsolete vars are boundp.
121 ;; doremi, doremi-set-new-value: Use these new list vars.
122 ;; doremi: Handle Emacs 23 mouse-wheel modifiers using doremi-intersection (ugly hack).
124 ;; doremi-*-key: fixed :type, clarified doc string about value.
126 ;; doremi: Use single-key-description in messages.
128 ;; doremi: Use doremi-set-new-value instead of wrapping input functions.
129 ;; Commented out setting redisplay-dont-pause to t.
130 ;; Added: doremi-set-new-value.
131 ;; oremi-boost-scale-factor: Clarified doc string.
132 ;; property -> parameter in all doc strings (RMS).
134 ;; doremi: Don't let switch-frame events quit the loop.
135 ;; Added: doremi-limit, doremi-wrap.
139 ;; Added :prefix to defgroup.
141 ;; doremi: Bind redisplay-dont-pause to `t' for Emacs 21.
142 ;; Use error-message-string to format error string.
144 ;; defvar -> defcustom. Added (defgroup doremi).
146 ;; doremi: Allowed for GROWTH-FN to be a function, not just a flag.
147 ;; Added initial value to initial prompt.
148 ;; Corrected addition of last event to unread-command-events.
149 ;; Improved error messages.
151 ;; Renamed do-re-mi* to doremi*.
152 ;; Prefixed everything here with doremi-.
153 ;; Changed convert-sequence-to-ring to ring-convert-sequence-to-ring.
155 ;; Added use of mouse wheel. Changed key sequences to events.
156 ;; Change prompt to add Meta info only for non-enumeration.
157 ;; Suppress keystroke echoing.
159 ;; Moved doremi-buffers to doremi-cmd.el.
160 ;; Commented-out commands test-*.
162 ;; Moved to doremi-frm.el: adjust-*, cycle-frame-configs,
163 ;; grow-font, move-frame-*, and apply of push-frame-config.
165 ;; Added: cycle-frame-configs.
166 ;; Apply push-frame-config to frame commands here.
168 ;; Added boost-*. Added error treatment to move-frame-*.
170 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172 ;; This program is free software; you can redistribute it and/or modify
173 ;; it under the terms of the GNU General Public License as published by
174 ;; the Free Software Foundation; either version 2, or (at your option)
175 ;; any later version.
177 ;; This program is distributed in the hope that it will be useful,
178 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
179 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
180 ;; GNU General Public License for more details.
182 ;; You should have received a copy of the GNU General Public License
183 ;; along with this program; see the file COPYING. If not, write to
184 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
185 ;; Floor, Boston, MA 02110-1301, USA.
187 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
191 (require 'ring+) ;; ring-convert-sequence-to-ring, ring-insert+extend,
192 ;; ring-member, ring-next, ring-previous
193 (require 'mwheel nil t) ; (no error if not found): mwheel-event-button
195 (and (< emacs-major-version 20) (eval-when-compile (require 'cl))) ;; when, unless
197 ;; In Emacs 20, because `mwheel.el' is not loaded, byte-compiling
198 ;; would give the following error messages, which can be ignored:
200 ;; While compiling doremi:
201 ;; ** reference to free variable mouse-wheel-down-event
202 ;; ** reference to free variable mouse-wheel-up-event
203 ;; While compiling the end of the data:
204 ;; ** the function mwheel-event-button is not known to be defined.
206 ;; This eliminates (only) the first of these two byte-compiler messages:
207 (defvar mouse-wheel-down-event)
208 (defvar mouse-wheel-up-event)
210 ;;;;;;;;;;;;;;;;;;;;;;;;;;
212 ;;; User Options (Variables)
216 "Do Re Mi: Incremental change using arrow keys or mouse wheel.
217 Define commands to perform repetitive or incremental operations."
218 :prefix "doremi-" :group 'convenience
219 :link `(url-link :tag "Send Bug Report"
220 ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\
222 &body=Describe bug here, starting with `emacs -q'. \
223 Don't forget to mention your Emacs and library versions."))
224 :link '(url-link :tag "Other Libraries by Drew"
225 "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries")
226 :link '(url-link :tag "Download"
227 "http://www.emacswiki.org/cgi-bin/wiki/doremi.el")
228 :link '(url-link :tag "Description"
229 "http://www.emacswiki.org/cgi-bin/wiki/Doremi")
230 :link '(emacs-commentary-link :tag "Commentary" "doremi"))
233 (defcustom doremi-up-keys '(up)
234 "*Keys (events) associated with one direction of adjusting by `doremi'.
235 The other direction is associated with `doremi-down-keys'.
237 The value must be a list of keyboard events: characters or symbols.
238 For example, a list element might be `?\C-p' or `prior'."
239 :type '(repeat (restricted-sexp :match-alternatives (integerp symbolp))) :group 'doremi)
242 (defcustom doremi-down-keys '(down)
243 "*Keys (events) associated with one direction of adjusting by `doremi'.
244 The other direction is associated with `doremi-up-keys'.
246 The value must be a list of keyboard events: characters or symbols.
247 For example, a list element might be `?\C-n' or `next'."
248 :type '(repeat (restricted-sexp :match-alternatives (integerp symbolp))) :group 'doremi)
251 (defcustom doremi-boost-up-keys '(M-up)
252 "*Like `doremi-up-keys', but increments by `doremi-boost-scale-factor'.
254 The value must be a list of keyboard events: characters or symbols.
255 For example, a list element might be `?\M-p' or `S-prior'."
256 :type '(repeat (restricted-sexp :match-alternatives (integerp symbolp))) :group 'doremi)
259 (defcustom doremi-boost-down-keys '(M-down)
260 "*Like `doremi-down-keys', but increments by `doremi-boost-scale-factor'.
262 The value must be a list of keyboard events: characters or symbols.
263 For example, a list element might be `?\M-n' or `S-next'."
264 :type '(repeat (restricted-sexp :match-alternatives (integerp symbolp))) :group 'doremi)
267 (defcustom doremi-boost-scale-factor 10
268 "*Factor to boost incremental change of numerical properties.
269 Using `doremi-boost-up-keys' or `doremi-boost-down-keys', instead of
270 `doremi-up-keys' or `doremi-down-keys' means that the increment is
271 this many times larger. Using a modifier key with the mouse wheel has
272 the same effect as using `doremi-boost-up-keys' or
273 `doremi-boost-down-keys'."
274 :type 'integer :group 'doremi)
276 ;; Originally, the key-variable options were for a single key, not a list of keys.
277 ;; Top-level warning when load the library.
278 (when (or (boundp 'doremi-up-key) (boundp 'doremi-boost-up-key)
279 (boundp 'doremi-down-key) (boundp 'doremi-boost-down-key))
280 (message "WARNING: Single-key options `doremi-...-key' are OBSOLETE. Use `doremi-...-keys'."))
282 ;;; Non-Interactive Functions
284 (defun doremi (setter-fn init-val incr &optional growth-fn enum allow-new-p)
285 "Use arrow keys and/or mouse wheel to adjust some parameter.
287 Variables `doremi-up-keys' and `doremi-down-keys' are variables that
288 you can assign to any key sequences. You can use these keys or the
289 mouse wheel to dynamically adjust any parameter. The keys can be held
290 down for continual adjustment.
292 Example parameters include background color and font size, but a
293 parameter can be anything that is adjustable in any of these ways:
294 * A numerical parameter that can be incremented or decremented, such
296 * A parameter that can take on one of several values (an enumerated
297 choice), such as a frame background color.
298 * A parameter that has an associated function to change its value
301 SETTER-FN is a function that adjusts the parameter. Two forms:
302 1) It takes a value as argument and sets the parameter to this value.
303 2) It is a \"growth\" function, which takes an increment as argument
304 and incrementally adjusts the value of the parameter.
306 Note that \"growth\" function really means, here, that the function
307 takes an increment as argument and does the incrementation (or
308 whatever) itself. It is contrasted with an absolute SETTER-FN that
309 just uses a value that is incremented by `doremi'. The difference is
310 which function does the incrementing, SETTER-FN or `doremi'.
312 In case #1, the new parameter value _must_ be returned by SETTER-FN.
313 In case #2, the new parameter value should be returned by SETTER-FN,
314 so that it can be echoed to the user.
316 INIT-VAL is the initial value for adjustment. In the case of an
317 incremental growth function (case #2), this is ignored.
319 INCR is an adjustment increment.
320 For an absolute SETTER-FN (#1), this is applied to INIT-VAL before
321 calling the function. If ENUM is non-nil, then INCR is ignored.
322 For an incremental growth function, this is passed to the function.
324 INCR can be a number or a list of numbers. When it is a list of
325 numbers, each is incremented or decremented (and possibly boosted by
326 `doremi-boost-scale-factor' - see below).
328 If GROWTH-FN is non-nil, then SETTER-FN is an incremental growth
329 function (case #2), and it is called with INCR as its only argument.
330 If GROWTH-FN is a function, then it is used as an alternative growth
331 function. In this case, SETTER-FN is called for `doremi-up-keys'
332 and GROWTH-FN is called for `doremi-down-keys' (mouse wheel is
335 ENUM is a choice-enumeration sequence (list, array, string...).
336 If ENUM is non-nil, then it is converted to a ring (circular
337 structure), and `doremi-up-keys' and `doremi-down-keys' set the
338 parameter to `ring-next' and `ring-previous' values, respectively.
340 If ENUM is non-nil, then ALLOW-NEW-P defines what happens if INIT-VAL
341 is not a member of ENUM. If ALLOW-NEW-P is nil, then an error is
342 raised. If non-nil, then INIT-VAL is added (to the ring created from
343 ENUM). If the symbol `extend', then if the ring is full it is
344 extended to include INIT-VAL; other non-nil values cause the oldest
345 item in a full ring to be dropped.
347 For numerical parameters (not enumerated choices), there are actually
348 two levels of incrementation. For faster incrementation, you can use
349 `doremi-boost-up-keys' and `doremi-boost-down-keys', or you can use
350 any keyboard modifier(s) (Shift, Meta, Control...) with the mouse
351 wheel. Incrementation is then `doremi-boost-scale-factor' times
354 For examples of using `doremi', see the source code of libraries
355 `doremi.el', `doremi-frm.el', and `doremi-cmd.el'."
356 (setq incr (or incr 1))
357 (let ((new-incr incr))
358 ;; $$$$ (redisplay-dont-pause t)) ; To give continual feedback.
359 ;; Convert sequence of values (list, array, vector, string) to a ring.
360 (when (and enum (sequencep enum)) (setq enum (ring-convert-sequence-to-ring enum)))
362 ;; Loop. Prompt, read event, and act on arrow-key or mouse-wheel event.
363 (let ((prompt (format "Use %s, %s, or mouse wheel to adjust value"
364 (single-key-description (car doremi-up-keys))
365 (single-key-description (car doremi-down-keys))))
366 (keys (append doremi-up-keys doremi-down-keys
367 doremi-boost-up-keys doremi-boost-down-keys))
368 (echo-keystrokes 0) ; Suppress keystroke echoing.
369 (wheel-down (if (boundp 'mouse-wheel-up-event)
371 'wheel-down)) ; Emacs 20.
372 (wheel-up (if (boundp 'mouse-wheel-down-event)
373 mouse-wheel-down-event
374 'wheel-up)) ; Emacs 20.
376 (unless enum (setq prompt (concat prompt " (modifier key: faster)")))
377 (setq prompt (format (concat prompt ". Value now: %s") init-val)
379 (while (progn (setq evnt (read-event prompt)
381 (or (member evnt keys)
383 (member (event-basic-type (car evnt))
384 `(switch-frame mouse-wheel mouse-2
385 ,wheel-up ,wheel-down)))))
386 ;; Set up the proper increment value.
387 (cond ((member evnt doremi-up-keys) (setq new-incr incr)) ; +
388 ((member evnt doremi-down-keys) ; -
389 (setq new-incr (if (atom incr) (- incr) (mapcar #'- incr))))
390 ((member evnt doremi-boost-up-keys) ; ++
393 (* doremi-boost-scale-factor incr)
394 (mapcar #'(lambda (in) (* doremi-boost-scale-factor in)) incr))))
395 ((member evnt doremi-boost-down-keys) ; --
398 (* doremi-boost-scale-factor (- incr))
399 (mapcar #'(lambda (in) (* doremi-boost-scale-factor (- in))) incr))))
401 ;; Emacs 20 mouse wheel.
402 ((and (consp evnt) (equal 'mouse-wheel (event-basic-type (car evnt))))
403 (setq new-incr (if (< 0 (nth 2 evnt))
405 (if (atom incr) (- incr) (mapcar #'- incr))))
406 (when (event-modifiers evnt) ; Boost it
409 (* doremi-boost-scale-factor new-incr)
410 (mapcar #'(lambda (in) (* doremi-boost-scale-factor in)) new-incr)))))
412 ;; Emacs 21+ mouse wheel: `mwheel.el'
413 ;; Free vars here: `mouse-wheel-down-event', `mouse-wheel-up-event'.
414 ;; Those vars and function `mwheel-event-button' are defined in `mwheel.el'.
415 ((and (consp evnt) (member (event-basic-type (car evnt))
416 `(,wheel-up ,wheel-down)))
417 (let ((button (mwheel-event-button evnt)))
418 (cond ((eq button mouse-wheel-down-event) (setq new-incr incr))
419 ((eq button mouse-wheel-up-event)
420 (setq new-incr (if (atom incr) (- incr) (mapcar #'- incr))))
421 (t (error "`doremi', bad mwheel-scroll binding - report bug to %s%s%s%s"
422 "drew.adams" "@" "oracle" ".com"))))
423 (when (if (> emacs-major-version 22) ; Boost it
424 (doremi-intersection (event-modifiers evnt)
425 '(shift control meta alt hyper super))
426 (event-modifiers evnt))
429 (* doremi-boost-scale-factor new-incr)
430 (mapcar #'(lambda (in) (* doremi-boost-scale-factor in)) new-incr)))))
431 (t (error "`doremi', unexpected event: `%S' - report bug to %s%s%s%s"
432 evnt "drew.adams" "@" "oracle" ".com")))
433 (if (and (consp evnt) (memq (event-basic-type (car evnt)) '(mouse-2 switch-frame)))
434 (message save-prompt) ; Just skip mouse-2 event (ignore while using wheel).
436 ;; Adjust setting and update INIT-VAL. Four cases are treated separately:
437 ;; 1) ENUM non-nil: use `ring-next' and `ring-previous'.
438 ;; 2) SETTER-FN and GROWTH-FN are both "growth" functions: call one of them.
439 ;; 3) SETTER-FN is a "growth" function: call it on the INCR arg.
440 ;; 4) otherwise (absolute fn): increment INIT-VAL, then call SETTER-FN on it.
441 (condition-case failure
443 (cond (;; 1) Ring of values (enumeration list). Use `ring-next''...
445 ;; If INIT-VAL is not already in the ring, add it.
446 ;; Extend the ring size if ALLOW-NEW-P is `extend'.
447 (when (and allow-new-p (not (ring-member enum init-val)))
448 (ring-insert+extend enum init-val
449 (eq 'extend allow-new-p)))
450 (when (< (ring-length enum) 2)
451 (error "`doremi' - Need at least two alternatives: %s" enum))
452 (let* ((vec (cdr (cdr enum)))
453 (veclen (length vec)))
454 (if (and (numberp new-incr) (>= new-incr 0))
455 (doremi-set-new-value setter-fn (ring-next enum init-val))
456 (doremi-set-new-value setter-fn (ring-previous enum init-val)))))
458 ;; 2) Two incremental growth functions. Call one on (new) INCR only.
459 ((functionp growth-fn)
461 (if (and (numberp new-incr) (>= new-incr 0))
462 (doremi-set-new-value setter-fn new-incr)
463 (doremi-set-new-value growth-fn (- new-incr)))
464 (if (and (numberp (car new-incr)) (>= (car new-incr) 0))
465 (doremi-set-new-value setter-fn new-incr)
466 (doremi-set-new-value growth-fn (mapcar #'- new-incr)))))
468 ;; 3) Single incremental growth function. Call it on (new) INCR only.
469 (growth-fn (doremi-set-new-value setter-fn new-incr))
471 ;; 4) Otherwise. Increment value. Call setter function on new value.
472 ((and (numberp new-incr) (numberp init-val))
473 (doremi-set-new-value setter-fn (+ init-val new-incr)))
474 (t (error "`doremi' - Bad argument. INIT-VAL: %s, INCR: %s"
475 init-val new-incr))))
476 (error (error "%s" (error-message-string failure))))))
478 (setq unread-command-events (cons evnt unread-command-events)))))
480 (defun doremi-intersection (list1 list2)
481 "Set intersection of lists LIST1 and LIST2.
482 This is a non-destructive operation: it copies the data if necessary."
483 (and list1 list2 (if (equal list1 list2)
486 (unless (>= (length list1) (length list2))
487 (setq list1 (prog1 list2 (setq list2 list1)))) ; Swap them.
489 (when (member (car list2) list1)
490 (setq result (cons (car list2) result)))
491 (setq list2 (cdr list2)))
494 (defun doremi-set-new-value (setter-fn newval)
495 "Apply SETTER-FN to NEWVAL, and return NEWVAL. Display progress message."
496 (prog1 (setq newval (funcall setter-fn newval))
497 (message "Use %s, %s, or mouse wheel again. New value: %s"
498 (single-key-description (car doremi-up-keys))
499 (single-key-description (car doremi-down-keys))
502 (defun doremi-limit (value min max)
503 "Limit VALUE to MIN or MAX limit if either is overshot.
504 MIN or MAX = nil means no such limit.
505 Return the new, possibly limited value."
506 (cond ((and max (> value max)) max)
507 ((and min (< value min)) min)
511 ;; (defun doremi-wrap (value min max)
512 ;; "Wrap VALUE around if it overshoots MIN or MAX."
513 ;; (cond ((> value max) min)
514 ;; ((< value min) max)
517 (defun doremi-wrap (value min max)
518 "Wrap VALUE around if it overshoots MIN or MAX.
519 Return the new, wrapped value.
520 MAX must be greater than min."
523 (while (> new max) (setq new (- new del)))
524 (while (< new min) (setq new (+ new del)))
528 ;;; Example Commands. Uncomment these and try them to get the idea.
530 ;; See also the commands in `doremi-cmd.el' and `doremi-frm.el' for
534 ;; Uses an enumeration list, (buffer-list).
535 ;; (defun doremi-buffers+ ()
536 ;; "Successively cycle among existing buffers."
538 ;; (doremi (lambda (newval) (switch-to-buffer newval 'norecord) newval)
544 ;; Test command that uses an enumeration list.
545 ;; This command changes nothing. It just echoes successive values.
546 ;; (defun test-list+ ()
548 ;; (doremi (lambda (newval) newval) 'c 1 nil '(a b c d e f g)))
550 ;; Test command that uses an enumeration list.
551 ;; In this test, the init-val is not a member of the enumeration list.
552 ;; An error is raised.
553 ;; This command changes nothing. It just echoes successive values.
554 ;; (defun test-list-prohibit-nonmember+ ()
556 ;; (doremi (lambda (newval) newval) 'c 1 nil '(a b)))
558 ;; Test command that uses an enumeration list.
559 ;; In this test, the init-val is not a member of the enumeration list.
560 ;; Because of non-nil 6th arg ALLOW-NEW-P, the initial value 'c is added
561 ;; to the enumeration.
562 ;; This command changes nothing. It just echoes successive values.
563 ;; (defun test-list-allow-nonmember+ ()
565 ;; (doremi (lambda (newval) newval) 'c 1 nil '(a b) t))
567 ;; Test command that uses an enumeration list.
568 ;; In this test, the init-val is not a member of the enumeration list.
569 ;; Because 6th arg ALLOW-NEW-P is 'extend, the enumeration is enlarged
570 ;; to include the initial value 'c.
571 ;; This command changes nothing. It just echoes successive values.
572 ;; (defun test-list-allow-nonmember+extend+ ()
574 ;; (doremi (lambda (newval) newval) 'c 1 nil '(a b) 'extend))
576 ;;;;;;;;;;;;;;;;;;;;;;;;;
580 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
581 ;;; doremi.el ends here