Mercurial > hg > xemacs-beta
diff lisp/map-ynp.el @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | abe6d1db359e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/map-ynp.el Mon Aug 13 11:28:15 2007 +0200 @@ -0,0 +1,290 @@ +;;; map-ynp.el --- General-purpose boolean question-asker. + +;; Copyright (C) 1991-1995, 1997 Free Software Foundation, Inc. + +;; Author: Roland McGrath <roland@gnu.ai.mit.edu> +;; Keywords: lisp, extensions, dumped + +;; This file is part of XEmacs. + +;; XEmacs is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; XEmacs is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with XEmacs; see the file COPYING. If not, write to the Free +;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. + +;;; Synched up with: Emacs/Mule zeta. + +;;; Commentary: + +;; This file is dumped with XEmacs. + +;; map-y-or-n-p is a general-purpose question-asking function. +;; It asks a series of y/n questions (a la y-or-n-p), and decides to +;; applies an action to each element of a list based on the answer. +;; The nice thing is that you also get some other possible answers +;; to use, reminiscent of query-replace: ! to answer y to all remaining +;; questions; ESC or q to answer n to all remaining questions; . to answer +;; y once and then n for the remainder; and you can get help with C-h. + +;;; Code: + +(defun map-y-or-n-p (prompter actor list &optional help action-alist + no-cursor-in-echo-area) + "Ask a series of boolean questions. +Takes args PROMPTER ACTOR LIST, and optional args HELP and ACTION-ALIST. + +LIST is a list of objects, or a function of no arguments to return the next +object or nil. + +If PROMPTER is a string, the prompt is \(format PROMPTER OBJECT\). If not +a string, PROMPTER is a function of one arg (an object from LIST), which +returns a string to be used as the prompt for that object. If the return +value is not a string, it may be nil to ignore the object or non-nil to act +on the object without asking the user. + +ACTOR is a function of one arg (an object from LIST), +which gets called with each object that the user answers `yes' for. + +If HELP is given, it is a list (OBJECT OBJECTS ACTION), +where OBJECT is a string giving the singular noun for an elt of LIST; +OBJECTS is the plural noun for elts of LIST, and ACTION is a transitive +verb describing ACTOR. The default is \(\"object\" \"objects\" \"act on\"\). + +At the prompts, the user may enter y, Y, or SPC to act on that object; +n, N, or DEL to skip that object; ! to act on all following objects; +ESC or q to exit (skip all following objects); . (period) to act on the +current object and then exit; or \\[help-command] to get help. + +If ACTION-ALIST is given, it is an alist (KEY FUNCTION HELP) of extra keys +that will be accepted. KEY is a character; FUNCTION is a function of one +arg (an object from LIST); HELP is a string. When the user hits KEY, +FUNCTION is called. If it returns non-nil, the object is considered +\"acted upon\", and the next object from LIST is processed. If it returns +nil, the prompt is repeated for the same object. + +Final optional argument NO-CURSOR-IN-ECHO-AREA non-nil says not to set +`cursor-in-echo-area' while prompting. + +This function uses `query-replace-map' to define the standard responses, +but not all of the responses which `query-replace' understands +are meaningful here. + +Returns the number of actions taken." + (let* ((actions 0) + user-keys mouse-event map prompt char elt def + ;; Non-nil means we should use mouse menus to ask. + ;; use-menus + ;;delayed-switch-frame + (next (if (or (and list (symbolp list)) + (subrp list) + (compiled-function-p list) + (and (consp list) + (eq (car list) 'lambda))) + #'(lambda () (setq elt (funcall list))) + #'(lambda () + (if list + (progn + (setq elt (car list) + list (cdr list)) + t) + nil))))) + (if (should-use-dialog-box-p) + ;; Make a list describing a dialog box. + (let (;; (object (capitalize (or (nth 0 help) "object"))) + ;; (objects (capitalize (or (nth 1 help) "objects"))) + ;; (action (capitalize (or (nth 2 help) "act on"))) + ) + (setq map `(("Yes" . act) ("No" . skip) +; bogus crap. --ben +; ((, (if help +; (capitalize +; (or (nth 3 help) +; (concat action " All " objects))) +; "Do All")) . automatic) +; ((, (if help +; (capitalize +; (or (nth 4 help) +; (concat action " " object " And Quit"))) +; "Do it and Quit")) . act-and-exit) +; ((, (capitalize +; (or (and help (nth 5 help)) "Quit"))) +; . exit) + ("Yes All" . automatic) + ("No All" . exit) + ("Cancel" . quit) + ,@(mapcar #'(lambda (elt) + (cons (capitalize (nth 2 elt)) + (vector (nth 1 elt)))) + action-alist)) + mouse-event last-command-event)) + (setq user-keys (if action-alist + (concat (mapconcat #'(lambda (elt) + (key-description + (if (characterp (car elt)) + ;; XEmacs + (char-to-string (car elt)) + (car elt)))) + action-alist ", ") + " ") + "") + ;; Make a map that defines each user key as a vector containing + ;; its definition. + ;; XEmacs + map (let ((foomap (make-sparse-keymap))) + (mapcar #'(lambda (elt) + (define-key + foomap + (if (characterp (car elt)) + (char-to-string (car elt)) + (car elt)) + (vector (nth 1 elt)))) + action-alist) + (set-keymap-parents foomap (list query-replace-map)) + foomap))) + (unwind-protect + (progn + (if (stringp prompter) + (setq prompter `(lambda (object) + (format ,prompter object)))) + (while (funcall next) + (setq prompt (funcall prompter elt)) + (cond ((stringp prompt) + ;; Prompt the user about this object. + (setq quit-flag nil) + (if mouse-event ; XEmacs + (setq def (or (get-dialog-box-response + mouse-event + (cons prompt map)) + 'quit)) + ;; Prompt in the echo area. + (let ((cursor-in-echo-area (not no-cursor-in-echo-area))) + (display-message + 'prompt + (format "%s(y, n, !, ., q, %sor %s) " + prompt user-keys + (key-description (vector help-char)))) + (setq char (next-command-event)) + ;; Show the answer to the question. + (display-message + 'prompt + (format + "%s(y, n, !, ., q, %sor %s) %s" + prompt user-keys + (key-description (vector help-char)) + (single-key-description char)))) + (setq def (lookup-key map (vector char)))) + (cond ((eq def 'exit) + (setq next #'(lambda () nil))) + ((eq def 'act) + ;; Act on the object. + (funcall actor elt) + (setq actions (1+ actions))) + ((eq def 'skip) + ;; Skip the object. + ) + ((eq def 'act-and-exit) + ;; Act on the object and then exit. + (funcall actor elt) + (setq actions (1+ actions) + next (function (lambda () nil)))) + ((or (eq def 'quit) (eq def 'exit-prefix)) + (setq quit-flag t) + (setq next `(lambda () + (setq next ',next) + ',elt))) + ((eq def 'automatic) + ;; Act on this and all following objects. + ;; (if (funcall prompter elt) ; Emacs + (if (eval (funcall prompter elt)) + (progn + (funcall actor elt) + (setq actions (1+ actions)))) + (while (funcall next) + ;; (funcall prompter elt) ; Emacs + (if (eval (funcall prompter elt)) + (progn + (funcall actor elt) + (setq actions (1+ actions)))))) + ((eq def 'help) + (with-output-to-temp-buffer "*Help*" + (princ + (let ((object (if help (nth 0 help) "object")) + (objects (if help (nth 1 help) "objects")) + (action (if help (nth 2 help) "act on"))) + (concat + (format "Type SPC or `y' to %s the current %s; +DEL or `n' to skip the current %s; +! to %s all remaining %s; +ESC or `q' to exit;\n" + action object object action objects) + (mapconcat (function + (lambda (elt) + (format "%c to %s" + (nth 0 elt) + (nth 2 elt)))) + action-alist + ";\n") + (if action-alist ";\n") + (format "or . (period) to %s \ +the current %s and exit." + action object)))) + (save-excursion + (set-buffer standard-output) + (help-mode))) + + (setq next `(lambda () + (setq next ',next) + ',elt))) + ((vectorp def) + ;; A user-defined key. + (if (funcall (aref def 0) elt) ;Call its function. + ;; The function has eaten this object. + (setq actions (1+ actions)) + ;; Regurgitated; try again. + (setq next `(lambda () + (setq next ',next) + ',elt)))) + ;((and (consp char) ; Emacs + ; (eq (car char) 'switch-frame)) + ; ;; switch-frame event. Put it off until we're done. + ; (setq delayed-switch-frame char) + ; (setq next `(lambda () + ; (setq next ',next) + ; ',elt))) + (t + ;; Random char. + (message "Type %s for help." + (key-description (vector help-char))) + (beep) + (sit-for 1) + (setq next `(lambda () + (setq next ',next) + ',elt))))) + ((eval prompt) + (progn + (funcall actor elt) + (setq actions (1+ actions))))))) + ;;(if delayed-switch-frame + ;; (setq unread-command-events + ;; (cons delayed-switch-frame unread-command-events)))) + ;; ((eval prompt) + ;; (progn + ;; (funcall actor elt) + ;; (setq actions (1+ actions))))) + ) + ;; Clear the last prompt from the minibuffer. + (clear-message 'prompt) + ;; Return the number of actions that were taken. + actions)) + +;;; map-ynp.el ends here