aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/ChangeLog16
-rw-r--r--lisp/obsolete/yow.el2
-rw-r--r--lisp/play/cookie1.el169
3 files changed, 145 insertions, 42 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 7c6a59c75f7..99072b43f61 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,19 @@
12013-06-21 Glenn Morris <rgm@gnu.org>
2
3 * play/cookie1.el (cookie): New custom group.
4 (cookie-file): New option.
5 (cookie-check-file): New function.
6 (cookie): Make it interactive. Make start and end messages optional.
7 Interactively, display the result. Default to cookie-file.
8 (cookie-insert): Default to cookie-file.
9 (cookie-snarf): Make start and end messages optional.
10 Default to cookie-file. Use with-temp-buffer.
11 (cookie-read): Rename from read-cookie.
12 Make start and end messages optional. Default to cookie-file.
13 (cookie-shuffle-vector): Rename from shuffle-vector. Use dotimes.
14 (cookie-apropos, cookie-doctor): New functions, copied from yow.el
15 * obsolete/yow.el (read-zippyism): Use new name for read-cookie.
16
12013-06-21 Leo Liu <sdl.web@gmail.com> 172013-06-21 Leo Liu <sdl.web@gmail.com>
2 18
3 * progmodes/octave.el (octave-mode): Backward compatibility fix. 19 * progmodes/octave.el (octave-mode): Backward compatibility fix.
diff --git a/lisp/obsolete/yow.el b/lisp/obsolete/yow.el
index 42bb0a0b354..abada670d6c 100644
--- a/lisp/obsolete/yow.el
+++ b/lisp/obsolete/yow.el
@@ -60,7 +60,7 @@
60(defsubst read-zippyism (prompt &optional require-match) 60(defsubst read-zippyism (prompt &optional require-match)
61 "Read a Zippyism from the minibuffer with completion, prompting with PROMPT. 61 "Read a Zippyism from the minibuffer with completion, prompting with PROMPT.
62If optional second arg is non-nil, require input to match a completion." 62If optional second arg is non-nil, require input to match a completion."
63 (read-cookie prompt yow-file yow-load-message yow-after-load-message 63 (cookie-read prompt yow-file yow-load-message yow-after-load-message
64 require-match)) 64 require-match))
65 65
66;;;###autoload 66;;;###autoload
diff --git a/lisp/play/cookie1.el b/lisp/play/cookie1.el
index d060c31aebc..69cf4d538b2 100644
--- a/lisp/play/cookie1.el
+++ b/lisp/play/cookie1.el
@@ -25,11 +25,10 @@
25;;; Commentary: 25;;; Commentary:
26 26
27;; Support for random cookie fetches from phrase files, used for such 27;; Support for random cookie fetches from phrase files, used for such
28;; critical applications as emulating Zippy the Pinhead and confounding 28;; critical applications as confounding the NSA Trunk Trawler.
29;; the NSA Trunk Trawler.
30;; 29;;
31;; The two entry points are `cookie' and `cookie-insert'. The helper 30;; The two entry points are `cookie' and `cookie-insert'. The helper
32;; function `shuffle-vector' may be of interest to programmers. 31;; function `cookie-shuffle-vector' may be of interest to programmers.
33;; 32;;
34;; The code expects phrase files to be in one of two formats: 33;; The code expects phrase files to be in one of two formats:
35;; 34;;
@@ -49,32 +48,62 @@
49;; This code derives from Steve Strassmann's 1987 spook.el package, but 48;; This code derives from Steve Strassmann's 1987 spook.el package, but
50;; has been generalized so that it supports multiple simultaneous 49;; has been generalized so that it supports multiple simultaneous
51;; cookie databases and fortune files. It is intended to be called 50;; cookie databases and fortune files. It is intended to be called
52;; from other packages such as yow.el and spook.el. 51;; from other packages such as spook.el.
53 52
54;;; Code: 53;;; Code:
55 54
55(defgroup cookie nil
56 "Random cookies from phrase files."
57 :prefix "cookie-"
58 :group 'games)
59
60(defcustom cookie-file nil
61 "Default phrase file for cookie functions."
62 :type '(choice (const nil) file)
63 :group 'cookie
64 :version "24.4")
65
56(defconst cookie-delimiter "\n%%\n\\|\n%\n\\|\0" 66(defconst cookie-delimiter "\n%%\n\\|\n%\n\\|\0"
57 "Delimiter used to separate cookie file entries.") 67 "Delimiter used to separate cookie file entries.")
58 68
59(defvar cookie-cache (make-vector 511 0) 69(defvar cookie-cache (make-vector 511 0)
60 "Cache of cookie files that have already been snarfed.") 70 "Cache of cookie files that have already been snarfed.")
61 71
72(defun cookie-check-file (file)
73 "Return either FILE or `cookie-file'.
74Signal an error if the result is nil or not readable."
75 (or (setq file (or file cookie-file)) (user-error "No phrase file specified"))
76 (or (file-readable-p file) (user-error "Cannot read file `%s'" file))
77 file)
78
62;;;###autoload 79;;;###autoload
63(defun cookie (phrase-file startmsg endmsg) 80(defun cookie (phrase-file &optional startmsg endmsg)
64 "Return a random phrase from PHRASE-FILE. 81 "Return a random phrase from PHRASE-FILE.
65When the phrase file is read in, display STARTMSG at the beginning 82When the phrase file is read in, display STARTMSG at the beginning
66of load, ENDMSG at the end." 83of load, ENDMSG at the end.
67 (let ((cookie-vector (cookie-snarf phrase-file startmsg endmsg))) 84Interactively, PHRASE-FILE defaults to `cookie-file', unless that
68 (shuffle-vector cookie-vector) 85is nil or a prefix argument is used."
69 (aref cookie-vector 0))) 86 (interactive (list (if (or current-prefix-arg (not cookie-file))
87 (read-file-name "Cookie file: " nil
88 cookie-file t cookie-file)
89 cookie-file) nil nil))
90 (setq phrase-file (cookie-check-file phrase-file))
91 (let ((cookie-vector (cookie-snarf phrase-file startmsg endmsg))
92 res)
93 (cookie-shuffle-vector cookie-vector)
94 (setq res (aref cookie-vector 0))
95 (if (called-interactively-p 'interactive)
96 (message "%s" res)
97 res)))
70 98
71;;;###autoload 99;;;###autoload
72(defun cookie-insert (phrase-file &optional count startmsg endmsg) 100(defun cookie-insert (phrase-file &optional count startmsg endmsg)
73 "Insert random phrases from PHRASE-FILE; COUNT of them. 101 "Insert random phrases from PHRASE-FILE; COUNT of them.
74When the phrase file is read in, display STARTMSG at the beginning 102When the phrase file is read in, display STARTMSG at the beginning
75of load, ENDMSG at the end." 103of load, ENDMSG at the end."
104 (setq phrase-file (cookie-check-file phrase-file))
76 (let ((cookie-vector (cookie-snarf phrase-file startmsg endmsg))) 105 (let ((cookie-vector (cookie-snarf phrase-file startmsg endmsg)))
77 (shuffle-vector cookie-vector) 106 (cookie-shuffle-vector cookie-vector)
78 (let ((start (point))) 107 (let ((start (point)))
79 (insert ?\n) 108 (insert ?\n)
80 (cookie1 (min (- (length cookie-vector) 1) (or count 1)) cookie-vector) 109 (cookie1 (min (- (length cookie-vector) 1) (or count 1)) cookie-vector)
@@ -89,12 +118,11 @@ of load, ENDMSG at the end."
89 (cookie1 (1- arg) cookie-vec)))) 118 (cookie1 (1- arg) cookie-vec))))
90 119
91;;;###autoload 120;;;###autoload
92(defun cookie-snarf (phrase-file startmsg endmsg) 121(defun cookie-snarf (phrase-file &optional startmsg endmsg)
93 "Reads in the PHRASE-FILE, returns it as a vector of strings. 122 "Reads in the PHRASE-FILE, returns it as a vector of strings.
94Emit STARTMSG and ENDMSG before and after. Caches the result; second 123Emit STARTMSG and ENDMSG before and after. Caches the result; second
95and subsequent calls on the same file won't go to disk." 124and subsequent calls on the same file won't go to disk."
96 (or (file-readable-p phrase-file) 125 (setq phrase-file (cookie-check-file phrase-file))
97 (error "Cannot read file `%s'" phrase-file))
98 (let ((sym (intern-soft phrase-file cookie-cache))) 126 (let ((sym (intern-soft phrase-file cookie-cache)))
99 (and sym (not (equal (symbol-function sym) 127 (and sym (not (equal (symbol-function sym)
100 (nth 5 (file-attributes phrase-file)))) 128 (nth 5 (file-attributes phrase-file))))
@@ -104,27 +132,25 @@ and subsequent calls on the same file won't go to disk."
104 (if sym 132 (if sym
105 (symbol-value sym) 133 (symbol-value sym)
106 (setq sym (intern phrase-file cookie-cache)) 134 (setq sym (intern phrase-file cookie-cache))
107 (message "%s" startmsg) 135 (if startmsg (message "%s" startmsg))
108 (save-excursion 136 (fset sym (nth 5 (file-attributes phrase-file)))
109 (let ((buf (generate-new-buffer "*cookie*")) 137 (let (result)
110 (result nil)) 138 (with-temp-buffer
111 (set-buffer buf)
112 (fset sym (nth 5 (file-attributes phrase-file)))
113 (insert-file-contents (expand-file-name phrase-file)) 139 (insert-file-contents (expand-file-name phrase-file))
114 (re-search-forward cookie-delimiter) 140 (re-search-forward cookie-delimiter)
115 (while (progn (skip-chars-forward " \t\n\r\f") (not (eobp))) 141 (while (progn (skip-chars-forward " \t\n\r\f") (not (eobp)))
116 (let ((beg (point))) 142 (let ((beg (point)))
117 (re-search-forward cookie-delimiter) 143 (re-search-forward cookie-delimiter)
118 (setq result (cons (buffer-substring beg (match-beginning 0)) 144 (setq result (cons (buffer-substring beg (match-beginning 0))
119 result)))) 145 result)))))
120 (kill-buffer buf) 146 (if endmsg (message "%s" endmsg))
121 (message "%s" endmsg) 147 (set sym (apply 'vector result))))))
122 (set sym (apply 'vector result)))))))
123 148
124(defun read-cookie (prompt phrase-file startmsg endmsg &optional require-match) 149(defun cookie-read (prompt phrase-file &optional startmsg endmsg require-match)
125 "Prompt with PROMPT and read with completion among cookies in PHRASE-FILE. 150 "Prompt with PROMPT and read with completion among cookies in PHRASE-FILE.
126STARTMSG and ENDMSG are passed along to `cookie-snarf'. 151STARTMSG and ENDMSG are passed along to `cookie-snarf'.
127Optional fifth arg REQUIRE-MATCH non-nil forces a matching cookie." 152Argument REQUIRE-MATCH non-nil forces a matching cookie."
153 (setq phrase-file (cookie-check-file phrase-file))
128 ;; Make sure the cookies are in the cache. 154 ;; Make sure the cookies are in the cache.
129 (or (intern-soft phrase-file cookie-cache) 155 (or (intern-soft phrase-file cookie-cache)
130 (cookie-snarf phrase-file startmsg endmsg)) 156 (cookie-snarf phrase-file startmsg endmsg))
@@ -141,24 +167,85 @@ Optional fifth arg REQUIRE-MATCH non-nil forces a matching cookie."
141 (put sym 'completion-alist alist)))) 167 (put sym 'completion-alist alist))))
142 nil require-match nil nil)) 168 nil require-match nil nil))
143 169
144; Thanks to Ian G Batten <BattenIG@CS.BHAM.AC.UK> 170(define-obsolete-function-alias 'read-cookie 'cookie-read "24.4")
145; [of the University of Birmingham Computer Science Department] 171
146; for the iterative version of this shuffle. 172;; Thanks to Ian G Batten <BattenIG@CS.BHAM.AC.UK>
147; 173;; [of the University of Birmingham Computer Science Department]
148;;;###autoload 174;; for the iterative version of this shuffle.
149(defun shuffle-vector (vector) 175(defun cookie-shuffle-vector (vector)
150 "Randomly permute the elements of VECTOR (all permutations equally likely)." 176 "Randomly permute the elements of VECTOR (all permutations equally likely)."
151 (let ((i 0) 177 (let ((len (length vector))
152 j 178 j temp)
153 temp 179 (dotimes (i len vector)
154 (len (length vector))) 180 (setq j (+ i (random (- len i)))
155 (while (< i len) 181 temp (aref vector i))
156 (setq j (+ i (random (- len i))))
157 (setq temp (aref vector i))
158 (aset vector i (aref vector j)) 182 (aset vector i (aref vector j))
159 (aset vector j temp) 183 (aset vector j temp))))
160 (setq i (1+ i)))) 184
161 vector) 185(define-obsolete-function-alias 'shuffle-vector 'cookie-shuffle-vector "24.4")
186
187
188(defun cookie-apropos (regexp phrase-file)
189 "Return a list of all entries matching REGEXP from PHRASE-FILE.
190Interactively, PHRASE-FILE defaults to `cookie-file', unless that
191is nil or a prefix argument is used.
192If called interactively, display a list of matches."
193 (interactive (list (read-regexp "Apropos phrase (regexp): ")
194 (if (or current-prefix-arg (not cookie-file))
195 (read-file-name "Cookie file: " nil
196 cookie-file t cookie-file)
197 cookie-file)))
198 (setq phrase-file (cookie-check-file phrase-file))
199 ;; Make sure phrases are loaded.
200 (cookie phrase-file)
201 (let* ((case-fold-search t)
202 (cookie-table-symbol (intern phrase-file cookie-cache))
203 (string-table (symbol-value cookie-table-symbol))
204 (matches nil)
205 (len (length string-table))
206 (i 0))
207 (save-match-data
208 (while (< i len)
209 (and (string-match regexp (aref string-table i))
210 (setq matches (cons (aref string-table i) matches)))
211 (setq i (1+ i))))
212 (and matches
213 (setq matches (sort matches 'string-lessp)))
214 (and (called-interactively-p 'interactive)
215 (cond ((null matches)
216 (message "No matches found."))
217 (t
218 (let ((l matches))
219 (with-output-to-temp-buffer "*Cookie Apropos*"
220 (while l
221 (princ (car l))
222 (setq l (cdr l))
223 (and l (princ "\n\n")))
224 (help-print-return-message))))))
225 matches))
226
227
228(declare-function doctor-ret-or-read "doctor" (arg))
229
230(defun cookie-doctor (phrase-file)
231 "Feed cookie phrases from PHRASE-FILE to the doctor.
232Interactively, PHRASE-FILE defaults to `cookie-file', unless that
233is nil or a prefix argument is used."
234 (interactive (list (if (or current-prefix-arg (not cookie-file))
235 (read-file-name "Cookie file: " nil
236 cookie-file t cookie-file)
237 cookie-file)))
238 (setq phrase-file (cookie-check-file phrase-file))
239 (doctor) ; start the psychotherapy
240 (message "")
241 (switch-to-buffer "*doctor*")
242 (sit-for 0)
243 (while (not (input-pending-p))
244 (insert (cookie phrase-file))
245 (sit-for 0)
246 (doctor-ret-or-read 1)
247 (doctor-ret-or-read 1)))
248
162 249
163(provide 'cookie1) 250(provide 'cookie1)
164 251