Re: [patch] sawfish.wm.util.prompt



Here's the promised patch to the prompt stuff.  Helper functions are
passed directly to prompt rather than via special variables, and the
prompt module should generally be more self-contained.  I also added a
docstring to the prompt function, and there's some minor cleanup.

NOTE: This does break backward-compatibility for third-party stuff that
uses prompt with completion.  I don't know how much of that there is out
there: if it's just using prompt-for-string there wont be a problem;
it's only a problem if the code was using the old method to pass
completion functions, etc.  The only scripts on the wiki I know of that
do that are:

 - prext, the (badly named and not completely working) module to access
   menus via prompt.
 - run-application
 - run-application-ng

None of these would be hard to adapt if this patch strikes folks as a
good idea.

diff --git a/lisp/sawfish/wm/util/prompt-extras.jl b/lisp/sawfish/wm/util/prompt-extras.jl
index 675639c..a810fc8 100644
--- a/lisp/sawfish/wm/util/prompt-extras.jl
+++ b/lisp/sawfish/wm/util/prompt-extras.jl
@@ -25,6 +25,13 @@
 
 (require 'rep.io.files)
 
+(defvar prompt-list-fold-case nil
+  "Whether prompt-from-list should ignore case.")
+
+(defvar prompt-file-exclude '"\\.(o|jlc|x)$|~$|^#.*#$|^\\.\\.?$"
+  "A regexp, if it matches the file being considered for completion, the file
+is rejected.")
+
 ;;; completion/validation functions
 
 (define (prompt-complete-filename word)
@@ -65,24 +72,27 @@
 	 (file-name-nondirectory (directory-file-name name)))
       abbrev)))
 
-(define (prompt-complete-from-list word)
-  (let (out)
-    (mapc (lambda (x)
-	    (when (string-match (concat ?^ (quote-regexp word))
-				x nil prompt-list-fold-case)
-	      (setq out (cons x out)))) prompt-list)
-    out))
-
-(define (prompt-validate-from-list name)
-  (if (null prompt-list-fold-case)
-      (and (member name prompt-list) name)
-    (catch 'exit
+(define (prompt-list-completor prompt-list)
+  (lambda (word)
+    (let (out)
       (mapc (lambda (x)
-	      (when (string-match (concat ?^ (quote-regexp name) ?$) x nil t)
-		(throw 'exit name))) prompt-list))))
+              (when (string-match (concat ?^ (quote-regexp word))
+                                  x nil prompt-list-fold-case)
+                (setq out (cons x out)))) prompt-list)
+      out)))
+
+(define (prompt-list-validator prompt-list)
+  (lambda (name)
+    (if (null prompt-list-fold-case)
+        (and (member name prompt-list) name)
+      (catch 'exit
+        (mapc (lambda (x)
+                (when (string-match (concat ?^ (quote-regexp name) ?$) x nil t)
+                  (throw 'exit name))) prompt-list)))))
 
 ;;; entry points
 
+(define filename-history (prompt-make-history))
 (define (prompt-for-file #!optional title existing start default)
   "Prompt for a file, if EXISTING is t only files which exist are
 allowed to be entered."
@@ -91,14 +101,17 @@ allowed to be entered."
   (setq start (if (stringp start)
 		  (expand-file-name start)
 		(file-name-as-directory default-directory)))
-  (let* ((prompt-completion-fun prompt-complete-filename)
-	 (prompt-validation-fun (and existing prompt-validate-filename))
-	 (prompt-abbrev-fun prompt-abbreviate-filename)
-	 (str (prompt title start)))
+  (let ((str (prompt #:title title
+                     #:start start
+                     #:completion-fun prompt-complete-filename
+                     #:validation-fun (and existing prompt-validate-filename)
+                     #:abbrev-fun prompt-abbreviate-filename
+                     #:history filename-history)))
     (when (and (string= str "") default)
       (setq str default))
     str))
 
+(define directory-name-history (prompt-make-history))
 (define (prompt-for-directory #!optional title existing start default)
   "Prompt for a directory, if EXISTING is t only files which exist are
 allowed to be entered."
@@ -106,10 +119,12 @@ allowed to be entered."
     (setq title "Enter filename:"))
   (unless (stringp start)
     (setq start (file-name-as-directory default-directory)))
-  (let* ((prompt-completion-fun prompt-complete-directory)
-	 (prompt-validation-fun (and existing prompt-validate-directory))
-	 (prompt-abbrev-fun prompt-abbreviate-filename)
-	 (str (prompt title start)))
+  (let ((str (prompt #:title title
+                     #:start start
+                     #:completion-fun prompt-complete-directory
+                     #:validation-fun (and existing prompt-validate-directory)
+                     #:abbrev-fun prompt-abbreviate-filename
+                     #:history directory-name-history)))
     (when (and (string= str "") default)
       (setq str default))
     str))
@@ -118,26 +133,30 @@ allowed to be entered."
   "Return a selected choice from the list of options (strings) OPTIONS.
 PROMPT is the title displayed, START the starting choice.
 Unless DONT-VALIDATE is t, only a member of PROMPT-LIST will be returned."
-  (let ((prompt-list options)
-	(prompt-completion-fun prompt-complete-from-list)
-	(prompt-validation-fun (if dont-validate
-				   nil
-				 prompt-validate-from-list)))
-    (prompt title start)))
+  (prompt #:title title
+          #:start start
+          #:completion-fun (prompt-list-completor options)
+          #:validation-fun (if dont-validate
+                               nil
+                             (prompt-list-validator options))))
 
 (define (prompt-for-string #!optional title start)
-  (let ((prompt-completion-fun prompt-complete-filename)
-	(prompt-validation-fun (lambda (#!rest) nil)))
-    (prompt (or title "Enter string: ") start)))
+  (prompt #:title (or title "Enter string: ")
+          #:start start
+          ;; XXX: Why is this completing on files???
+          #:completion-fun prompt-complete-filename))
 
 (define (prompt-for-number #!optional title)
   (let (num)
     (while (not (numberp num))
-      (setq num (read-from-string (prompt (or title "Enter number: ")))))
+      (setq num (read-from-string (prompt
+                                   #:title (or title "Enter number: ")))))
     num))
 
 (define (pwd-prompt title)
-  (let ((prompt-display-fun (lambda (string)
-			     (make-string (length string) ?*)))
-	(prompt-history nil))
-    (prompt-for-string title)))
+  "Prompt for a string, hiding the string behind asterisks (e.g., for
+a password)."
+  (prompt #:title title
+          #:history (make-fluid) ; Disable history
+          #:display-fun (lambda (string)
+                          (make-string (length string) ?*))))
diff --git a/lisp/sawfish/wm/util/prompt-wm.jl b/lisp/sawfish/wm/util/prompt-wm.jl
index 45067d1..45f6096 100644
--- a/lisp/sawfish/wm/util/prompt-wm.jl
+++ b/lisp/sawfish/wm/util/prompt-wm.jl
@@ -1,5 +1,4 @@
 ;; prompt-wm.jl -- prompt variants for windows/workspaces
-;; $Id: prompt-wm.jl,v 1.6 2000/09/11 07:44:42 john Exp $
 
 ;; Contributed by Dave Pearson <davep davep org>
 
@@ -44,11 +43,12 @@
                 (if (string-match re (car names))
                     (cons (car names) (names-matching re (cdr names)))
                   (names-matching re (cdr names))))))
-           (prompt-completion-fun
+           (complete-windows
             (lambda (text)
               (names-matching (format nil "^%s" text)
                               (sort (window-names (managed-windows)))))))
-    (let ((window-title (prompt (or title (_ "Window:")))))
+    (let ((window-title (prompt #:title (or title (_ "Window:"))
+                                #:completion-fun complete-windows)))
       (unless (zerop (length window-title))
         (cdr (assoc window-title (mapcar (lambda (w)
 					   (cons (window-name w) w))
@@ -71,10 +71,11 @@
                 (if (string-match re (car names))
                     (cons (car names) (names-matching re (cdr names)))
                   (names-matching re (cdr names))))))
-           (prompt-completion-fun
+           (complete-workspaces
             (lambda (text)
               (names-matching (format nil "^%s" text) (workspaces)))))
-    (let ((ws-title (prompt (or title (_ "Workspace:"))))
+    (let ((ws-title (prompt #:title (or title (_ "Workspace:"))
+                            #:completion-fun complete-workspaces))
           (wsl (workspaces)))
       (unless (zerop (length ws-title))
         (let ((where (member ws-title wsl)))
diff --git a/lisp/sawfish/wm/util/prompt.jl b/lisp/sawfish/wm/util/prompt.jl
index 845a90b..030445a 100644
--- a/lisp/sawfish/wm/util/prompt.jl
+++ b/lisp/sawfish/wm/util/prompt.jl
@@ -1,5 +1,5 @@
 ;; prompt.jl -- read line from user
-;; Time-stamp: <2000-02-25 22:02:54 tjp>
+;; Time-stamp: <Sat Sep 19 15:10:36 CDT 2009>
 ;;
 ;; Copyright (C) 2008 Sergey I. Sharybin <sharybin nm ru>
 ;; Copyright (C) 2000 Topi Paavola <tjp iki fi>
@@ -20,6 +20,7 @@
 	    prompt-for-function
 	    prompt-for-variable
 	    prompt-for-command
+            prompt-make-history
 
 	    ;; motion / editing commands
 	    prompt-backward-character
@@ -86,38 +87,32 @@
     "Regexp that determines which characters are to be considered part
 of a word when moving.")
 
-  (defvar prompt-file-exclude '"\\.(o|jlc|x)$|~$|^#.*#$|^\\.\\.?$"
-    "A regexp, if it matches the file being considered for completion, the file
-is rejected.")
-
-  (defvar prompt-list nil
-    "List of possible entries for prompt-from-list.")
-
-  (defvar prompt-list-fold-case nil
-    "Whether prompt-from-list should ignore case.")
-
-  (defvar prompt-history (make-ring 16)
-    "Ring buffer containing strings most-recently entered through the `prompt'
-function.")
-
   (defvar prompt-window-position
     (cons (- (quotient (screen-width) 2) 200) -200)
     "A cons cell defining the screen position at which the `prompt' window is
 displayed. See the `display-message' function for more details.")
 
-  (defvar prompt-result nil)
-  (defvar prompt-prompt nil)
-  (defvar prompt-completion-fun (lambda (#!rest) nil))
-  (defvar prompt-validation-fun (lambda (#!rest) nil))
-  (defvar prompt-abbrev-fun (lambda (#!rest) nil))
-  (defvar prompt-display-fun (lambda (#!rest) nil))
-  (defvar prompt-position 0)
-  (defvar prompt-completion-position nil)
-  (defvar prompt-completions nil)
-  (defvar prompt-completions-outdated nil)
-  (defvar prompt-history-pos nil)
-  (defvar prompt-saved nil)
-  (defvar prompt-attr nil)
+  (define (prompt-make-history)
+    "Make a receptacle for prompt history."
+    (make-fluid (make-ring 16)))
+
+  ;; Internal variables:
+  (define prompt-history-default (prompt-make-history))
+  (define prompt-history nil)
+  (define prompt-result nil)
+  (define prompt-prompt nil)
+  (define prompt-completion-fun nil)
+  (define prompt-validation-fun nil)
+  (define prompt-abbrev-fun nil)
+  (define prompt-display-fun nil)
+  (define prompt-position 0)
+  (define prompt-completion-position nil)
+  (define prompt-completions nil)
+  (define prompt-completions-outdated nil)
+  (define prompt-history-pos nil)
+  (define prompt-saved nil)
+  (define prompt-attr nil)
+
 
 ;; From merlin
 ;; But maybe better if we'd include this util?
@@ -136,13 +131,13 @@ displayed. See the `display-message' function for more details.")
       (assq key alist)
       (cons key default)))
 
-  (defun prompt-exit ()
+  (define (prompt-exit)
     "Cancel string input."
     (throw 'prompt-exit nil))
 
-  (defun prompt-accept ()
+  (define (prompt-accept)
     "End input and accept current string."
-    (let ((result (if (not (prompt-validation-fun prompt-result))
+    (let ((result (if (not prompt-validation-fun)
 		      prompt-result
 		    (prompt-validation-fun prompt-result))))
       (if result
@@ -153,7 +148,7 @@ displayed. See the `display-message' function for more details.")
 	    (throw 'prompt-exit result))
 	(beep))))
 
-  (defun prompt-next (count)
+  (define (prompt-next count)
     (interactive "p")
     (when prompt-history
       (setq count (- prompt-history-pos count))
@@ -172,21 +167,21 @@ displayed. See the `display-message' function for more details.")
       (prompt-end-of-line)
       (prompt-update-display)))
 
-  (defun prompt-previous (count)
+  (define (prompt-previous count)
     (interactive "p")
     (prompt-next (- count)))
 
-  (defun prompt-changed ()
+  (define (prompt-changed)
     (setq prompt-completions-outdated t))
 
-  (defun prompt-clear ()
+  (define (prompt-clear)
     "Clear input buffer."
     (setq prompt-result "")
     (setq prompt-position 0)
     (prompt-changed)
     (prompt-update-display))
 
-  (defun prompt-backspace ()
+  (define (prompt-backspace)
     "Remove previous character from buffer."
     (when (> prompt-position 0)
       (let ((cutoff (max (- prompt-position 1) 0)))
@@ -197,20 +192,20 @@ displayed. See the `display-message' function for more details.")
 	(prompt-changed)
 	(prompt-update-display))))
 
-  (defun prompt-kill-line ()
+  (define (prompt-kill-line)
     "Delete rest of line."
     (setq prompt-result (substring prompt-result 0 prompt-position))
     (prompt-changed)
     (prompt-update-display))
 
-  (defun prompt-move (num)
+  (define (prompt-move num)
     "Move NUM characters forward or backward."
     (let ((new-pos (+ prompt-position num)))
       (and (>= new-pos 0) (<= new-pos (length prompt-result))
 	   (setq prompt-position new-pos)
 	   (prompt-update-display))))
          
-  (defun prompt-forward-word ()
+  (define (prompt-forward-word)
     "Move to next non-word character."
     (setq prompt-position (1+ prompt-position))
     (while (and (< prompt-position (length prompt-result))
@@ -221,7 +216,7 @@ displayed. See the `display-message' function for more details.")
 			       (length prompt-result)))
     (prompt-update-display))
 
-  (defun prompt-backward-word ()
+  (define (prompt-backward-word)
     "Move to previous non-word character."
     (setq prompt-position (1- prompt-position))
     (while (and (> prompt-position 0)
@@ -231,25 +226,25 @@ displayed. See the `display-message' function for more details.")
     (setq prompt-position (max prompt-position 0))
     (prompt-update-display))
 
-  (defun prompt-forward-character ()
+  (define (prompt-forward-character)
     "Move forward one character."
     (prompt-move 1))
 
-  (defun prompt-backward-character ()
+  (define (prompt-backward-character)
     "Move backward one character."
     (prompt-move -1))
 
-  (defun prompt-beginning-of-line ()
+  (define (prompt-beginning-of-line)
     "Move to beginning of line."
     (setq prompt-position 0)
     (prompt-update-display))
 
-  (defun prompt-end-of-line ()
+  (define (prompt-end-of-line)
     "Move to end of line."
     (setq prompt-position (length prompt-result))
     (prompt-update-display))
 
-  (defun prompt-complete ()
+  (define (prompt-complete)
     (if (and (not prompt-completions-outdated) prompt-completion-position)
 	(let
 	    ((new (min (max 0 (- (length prompt-completions)
@@ -259,7 +254,7 @@ displayed. See the `display-message' function for more details.")
 		(if (= new prompt-completion-position)
 		    0
 		  new)))
-      (when (prompt-completion-fun prompt-result)
+      (when prompt-completion-fun
 	(let
 	    (compl)
 	  (setq prompt-completions (prompt-completion-fun prompt-result))
@@ -277,7 +272,7 @@ displayed. See the `display-message' function for more details.")
 	      (setq prompt-completion-position 0))))))
     (prompt-update-display))
 
-  (defun prompt-format-completions ()
+  (define (prompt-format-completions)
     (when (numberp prompt-completion-position)
       (let ((compl (nthcdr prompt-completion-position prompt-completions))
 	    (continued nil))
@@ -288,14 +283,14 @@ displayed. See the `display-message' function for more details.")
 	(concat (and (/= prompt-completion-position 0) "[...]\n")
 		(apply concat (mapcar (lambda (x)
 					(format nil "%s\n"
-						(if (prompt-abbrev-fun x)
+						(if prompt-abbrev-fun
 						    (prompt-abbrev-fun x)
 						  x)))
 				      compl))
 		continued))))
 
-  (defun prompt-update-display ()
-    (let ((result (if (prompt-display-fun prompt-result)
+  (define (prompt-update-display)
+    (let ((result (if prompt-display-fun
 		      (prompt-display-fun prompt-result)
 		   prompt-result))
 	 (completions (prompt-format-completions)))
@@ -318,7 +313,7 @@ displayed. See the `display-message' function for more details.")
              )))))
 
   ;; Insert all unbound keys to result.
-  (defun prompt-unbound-callback ()
+  (define (prompt-unbound-callback)
     (let ((key (current-event-string)))
       (setq prompt-result
 	    (concat (substring prompt-result 0 prompt-position)
@@ -329,8 +324,20 @@ displayed. See the `display-message' function for more details.")
       (prompt-update-display)
       t))
 
-  (defun prompt (#!optional title start attributes)
-    "Prompt the user for a string."
+  (define (prompt #!key title start attributes completion-fun
+                  validation-fun abbrev-fun display-fun history)
+    "Prompt the user for a string.  All of the keyword options are
+optional and have reasonable defaults.
+
+ - `title' is the message displayed to prompt the user.
+ - `start' is an initial string automatically entered into the prompt.
+ - `attributes' can be used to set text attributes.
+ - `completion-fun' is a function used for tab completion.
+ - `validation-fun' is a function that checks input for validity.
+ - `abbrev-fun' is used to abbreviate possible completions for display.
+ - `display-fun' can be used to change the way entered text is displayed.
+ - `history' contains history.  Use `prompt-make-history' to generate
+   an appropriate value."
     (unless (stringp title)
       (setq title "Enter string:"))
     (unless (string-match " $" title)
@@ -338,37 +345,45 @@ displayed. See the `display-message' function for more details.")
     (call-with-keyboard-grabbed
      (lambda ()
        (unwind-protect
-	   (let* ((override-keymap prompt-keymap)
-		  (prompt-result (or start ""))
-		  (prompt-prompt title)
-		  (prompt-position (length prompt-result))
-		  (prompt-history-pos 0)
-		  (prompt-saved nil)
-		  (prompt-attr attributes)
-		  (prompt-completion-position nil)
-		  (prompt-completions nil)
-		  (prompt-completions-outdated t)
-		  (unbound-key-hook (list prompt-unbound-callback)))
+           (let ((override-keymap prompt-keymap)
+                 (unbound-key-hook (list prompt-unbound-callback)))
+             (setq prompt-history (fluid (or history
+                                             prompt-history-default))
+                   prompt-completion-fun completion-fun
+                   prompt-validation-fun validation-fun
+                   prompt-abbrev-fun abbrev-fun
+                   prompt-display-fun display-fun
+                   prompt-result (or start "")
+                   prompt-prompt title
+                   prompt-position (length prompt-result)
+                   prompt-history-pos 0
+                   prompt-saved nil
+                   prompt-attr attributes
+                   prompt-completion-position nil
+                   prompt-completions nil
+                   prompt-completions-outdated t)
 	     (prompt-update-display)
 	     (catch 'prompt-exit
 	       (recursive-edit)))
 	 (display-message nil)))))
 
-  (defun prompt-for-symbol (#!optional title predicate validator)
-    (let ((prompt-completion-fun
-	      (lambda (x)
-		(mapcar symbol-name
-			(apropos (concat ?^ (quote-regexp x)) predicate))))
-	     (prompt-validation-fun
-	      (lambda (x)
-		(let
-		    ((symbol (intern x)))
-		  (if validator
-		      (and (validator symbol) symbol)
-		    symbol)))))
-      (prompt title)))
-
-  (defun prompt-for-function (#!optional title)
+  (define symbol-history (prompt-make-history))
+  (define (prompt-for-symbol #!optional title predicate validator #!key history)
+    (prompt #:title title
+            #:completion-fun (lambda (x)
+                               (mapcar symbol-name
+                                       (apropos (concat ?^ (quote-regexp x))
+                                                predicate)))
+            #:validation-fun (lambda (x)
+                               (let
+                                   ((symbol (intern x)))
+                                 (if validator
+                                     (and (validator symbol) symbol)
+                                   symbol)))
+            #:history (or history symbol-history)))
+
+  (define function-history (prompt-make-history))
+  (define (prompt-for-function #!optional title)
     "Prompt for a function."
     (prompt-for-symbol (or title "Enter name of function:")
 		       (lambda (x)
@@ -376,14 +391,19 @@ displayed. See the `display-message' function for more details.")
 			      (let ((value (symbol-value x)))
 				(or (functionp value)
 				    (macrop value)
-				    (special-form-p value)))))))
+				    (special-form-p value)))))
+                       #:history function-history))
 
-  (defun prompt-for-variable (#!optional title)
+  (define variable-history (prompt-make-history))
+  (define (prompt-for-variable #!optional title)
     "Prompt for a variable."
-    (prompt-for-symbol (or title "Enter name of variable:") boundp))
+    (prompt-for-symbol (or title "Enter name of variable:") boundp
+                       #:history variable-history))
 
-  (defun prompt-for-command (#!optional title)
-    (prompt-for-symbol title commandp commandp))
+  (define command-history (prompt-make-history))
+  (define (prompt-for-command #!optional title)
+    (prompt-for-symbol title commandp commandp
+                       #:history command-history))
 
 
 ;;; autoloads
-- 
Jeremy Hankins <nowan nowan org>
PGP fingerprint: 748F 4D16 538E 75D6 8333  9E10 D212 B5ED 37D0 0A03


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]