Mercurial > hg > xemacs-beta
annotate lisp/minibuf.el @ 5584:d469c668462e
#'load-terminal-library; load term files correctly for gnuclient consoles.
lisp/ChangeLog addition:
2011-10-17 Aidan Kehoe <kehoea@parhasard.net>
* startup.el (load-terminal-library):
Don't (getenv "TERM") here, call #'console-tty-terminal-type
instead, different gnuclient consoles can and should have
different terminal type function maps effective.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Tue, 18 Oct 2011 12:03:36 +0100 |
parents | 3bc58dc9d688 |
children | b7ae5f44b950 |
rev | line source |
---|---|
428 | 1 ;;; minibuf.el --- Minibuffer functions for XEmacs |
2 | |
3 ;; Copyright (C) 1992, 1993, 1994, 1997 Free Software Foundation, Inc. | |
442 | 4 ;; Copyright (C) 1995 Tinker Systems. |
771 | 5 ;; Copyright (C) 1995, 1996, 2000, 2002 Ben Wing. |
428 | 6 |
7 ;; Author: Richard Mlynarik | |
8 ;; Created: 2-Oct-92 | |
9 ;; Maintainer: XEmacs Development Team | |
10 ;; Keywords: internal, dumped | |
11 | |
12 ;; This file is part of XEmacs. | |
13 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
14 ;; XEmacs is free software: you can redistribute it and/or modify it |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
15 ;; under the terms of the GNU General Public License as published by the |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
16 ;; Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
17 ;; option) any later version. |
428 | 18 |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
19 ;; XEmacs is distributed in the hope that it will be useful, but WITHOUT |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
20 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
21 ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
22 ;; for more details. |
428 | 23 |
24 ;; You should have received a copy of the GNU General Public License | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5267
diff
changeset
|
25 ;; along with XEmacs. If not, see <http://www.gnu.org/licenses/>. |
428 | 26 |
27 ;;; Synched up with: all the minibuffer history stuff is synched with | |
28 ;;; 19.30. Not sure about the rest. | |
29 | |
30 ;;; Commentary: | |
31 | |
32 ;; This file is dumped with XEmacs. | |
33 | |
34 ;; Written by Richard Mlynarik 2-Oct-92 | |
35 | |
36 ;; 06/11/1997 - Use char-(after|before) instead of | |
37 ;; (following|preceding)-char. -slb | |
38 | |
39 ;;; Code: | |
40 | |
4734
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
41 (require 'cl) |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
42 |
428 | 43 (defgroup minibuffer nil |
5384
3889ef128488
Fix misspelled words, and some grammar, across the entire source tree.
Jerry James <james@xemacs.org>
parents:
5368
diff
changeset
|
44 "Controlling the behavior of the minibuffer." |
428 | 45 :group 'environment) |
46 | |
47 | |
48 (defcustom insert-default-directory t | |
49 "*Non-nil means when reading a filename start with default dir in minibuffer." | |
50 :type 'boolean | |
51 :group 'minibuffer) | |
52 | |
53 (defcustom minibuffer-history-uniquify t | |
54 "*Non-nil means when adding an item to a minibuffer history, remove | |
442 | 55 previous occurrences of the same item from the history list first, |
428 | 56 rather than just consing the new element onto the front of the list." |
57 :type 'boolean | |
58 :group 'minibuffer) | |
59 | |
60 (defvar minibuffer-completion-table nil | |
61 "Alist or obarray used for completion in the minibuffer. | |
62 This becomes the ALIST argument to `try-completion' and `all-completions'. | |
63 | |
64 The value may alternatively be a function, which is given three arguments: | |
65 STRING, the current buffer contents; | |
66 PREDICATE, the predicate for filtering possible matches; | |
67 CODE, which says what kind of things to do. | |
68 CODE can be nil, t or `lambda'. | |
69 nil means to return the best completion of STRING, nil if there is none, | |
70 or t if it is already a unique completion. | |
71 t means to return a list of all possible completions of STRING. | |
72 `lambda' means to return t if STRING is a valid completion as it stands.") | |
73 | |
74 (defvar minibuffer-completion-predicate nil | |
75 "Within call to `completing-read', this holds the PREDICATE argument.") | |
76 | |
77 (defvar minibuffer-completion-confirm nil | |
78 "Non-nil => demand confirmation of completion before exiting minibuffer.") | |
79 | |
438 | 80 (defcustom minibuffer-confirm-incomplete nil |
428 | 81 "If true, then in contexts where completing-read allows answers which |
82 are not valid completions, an extra RET must be typed to confirm the | |
438 | 83 response. This is helpful for catching typos, etc." |
84 :type 'boolean | |
85 :group 'minibuffer) | |
428 | 86 |
87 (defcustom completion-auto-help t | |
88 "*Non-nil means automatically provide help for invalid completion input." | |
89 :type 'boolean | |
90 :group 'minibuffer) | |
91 | |
92 (defcustom enable-recursive-minibuffers nil | |
93 "*Non-nil means to allow minibuffer commands while in the minibuffer. | |
94 More precisely, this variable makes a difference when the minibuffer window | |
95 is the selected window. If you are in some other window, minibuffer commands | |
96 are allowed even if a minibuffer is active." | |
97 :type 'boolean | |
98 :group 'minibuffer) | |
99 | |
100 (defcustom minibuffer-max-depth 1 | |
101 ;; See comment in #'minibuffer-max-depth-exceeded | |
102 "*Global maximum number of minibuffers allowed; | |
103 compare to enable-recursive-minibuffers, which is only consulted when the | |
104 minibuffer is reinvoked while it is the selected window." | |
105 :type '(choice integer | |
106 (const :tag "Indefinite" nil)) | |
107 :group 'minibuffer) | |
108 | |
109 ;; Moved to C. The minibuffer prompt must be setup before this is run | |
110 ;; and that can only be done from the C side. | |
111 ;(defvar minibuffer-setup-hook nil | |
112 ; "Normal hook run just after entry to minibuffer.") | |
113 | |
442 | 114 ;; see comment at list-mode-hook. |
115 (put 'minibuffer-setup-hook 'permanent-local t) | |
116 | |
428 | 117 (defvar minibuffer-exit-hook nil |
118 "Normal hook run just after exit from minibuffer.") | |
442 | 119 (put 'minibuffer-exit-hook 'permanent-local t) |
428 | 120 |
121 (defvar minibuffer-help-form nil | |
122 "Value that `help-form' takes on inside the minibuffer.") | |
123 | |
124 (defvar minibuffer-default nil | |
125 "Default value for minibuffer input.") | |
126 | |
127 (defvar minibuffer-local-map | |
128 (let ((map (make-sparse-keymap 'minibuffer-local-map))) | |
129 map) | |
130 "Default keymap to use when reading from the minibuffer.") | |
131 | |
132 (defvar minibuffer-local-completion-map | |
133 (let ((map (make-sparse-keymap 'minibuffer-local-completion-map))) | |
134 (set-keymap-parents map (list minibuffer-local-map)) | |
135 map) | |
136 "Local keymap for minibuffer input with completion.") | |
137 | |
138 (defvar minibuffer-local-must-match-map | |
139 (let ((map (make-sparse-keymap 'minibuffer-must-match-map))) | |
140 (set-keymap-parents map (list minibuffer-local-completion-map)) | |
141 map) | |
142 "Local keymap for minibuffer input with completion, for exact match.") | |
143 | |
144 ;; (define-key minibuffer-local-map "\C-g" 'abort-recursive-edit) | |
145 (define-key minibuffer-local-map "\C-g" 'minibuffer-keyboard-quit) ;; moved here from pending-del.el | |
146 (define-key minibuffer-local-map "\r" 'exit-minibuffer) | |
147 (define-key minibuffer-local-map "\n" 'exit-minibuffer) | |
148 | |
149 ;; Historical crock. Unused by anything but user code, if even that | |
150 ;(defvar minibuffer-local-ns-map | |
151 ; (let ((map (make-sparse-keymap 'minibuffer-local-ns-map))) | |
152 ; (set-keymap-parents map (list minibuffer-local-map)) | |
153 ; map) | |
154 ; "Local keymap for the minibuffer when spaces are not allowed.") | |
155 ;(define-key minibuffer-local-ns-map [space] 'exit-minibuffer) | |
156 ;(define-key minibuffer-local-ns-map [tab] 'exit-minibuffer) | |
157 ;(define-key minibuffer-local-ns-map [?\?] 'self-insert-and-exit) | |
158 | |
159 (define-key minibuffer-local-completion-map "\t" 'minibuffer-complete) | |
160 (define-key minibuffer-local-completion-map " " 'minibuffer-complete-word) | |
161 (define-key minibuffer-local-completion-map "?" 'minibuffer-completion-help) | |
162 (define-key minibuffer-local-must-match-map "\r" 'minibuffer-complete-and-exit) | |
163 (define-key minibuffer-local-must-match-map "\n" 'minibuffer-complete-and-exit) | |
164 | |
165 (define-key minibuffer-local-map "\M-n" 'next-history-element) | |
166 (define-key minibuffer-local-map "\M-p" 'previous-history-element) | |
167 (define-key minibuffer-local-map '[next] "\M-n") | |
168 (define-key minibuffer-local-map '[prior] "\M-p") | |
169 (define-key minibuffer-local-map "\M-r" 'previous-matching-history-element) | |
170 (define-key minibuffer-local-map "\M-s" 'next-matching-history-element) | |
171 (define-key minibuffer-local-must-match-map [next] | |
172 'next-complete-history-element) | |
173 (define-key minibuffer-local-must-match-map [prior] | |
174 'previous-complete-history-element) | |
175 | |
176 ;; This is an experiment--make up and down arrows do history. | |
177 (define-key minibuffer-local-map [up] 'previous-history-element) | |
178 (define-key minibuffer-local-map [down] 'next-history-element) | |
179 (define-key minibuffer-local-completion-map [up] 'previous-history-element) | |
180 (define-key minibuffer-local-completion-map [down] 'next-history-element) | |
181 (define-key minibuffer-local-must-match-map [up] 'previous-history-element) | |
182 (define-key minibuffer-local-must-match-map [down] 'next-history-element) | |
183 | |
184 (defvar read-expression-map (let ((map (make-sparse-keymap | |
185 'read-expression-map))) | |
186 (set-keymap-parents map | |
187 (list minibuffer-local-map)) | |
188 (define-key map "\M-\t" 'lisp-complete-symbol) | |
189 map) | |
190 "Minibuffer keymap used for reading Lisp expressions.") | |
191 | |
192 (defvar read-shell-command-map | |
193 (let ((map (make-sparse-keymap 'read-shell-command-map))) | |
194 (set-keymap-parents map (list minibuffer-local-map)) | |
195 (define-key map "\t" 'comint-dynamic-complete) | |
196 (define-key map "\M-\t" 'comint-dynamic-complete) | |
197 (define-key map "\M-?" 'comint-dynamic-list-completions) | |
198 map) | |
444 | 199 "Minibuffer keymap used by `shell-command' and related commands.") |
428 | 200 |
201 (defcustom use-dialog-box t | |
202 "*Variable controlling usage of the dialog box. | |
203 If nil, the dialog box will never be used, even in response to mouse events." | |
204 :type 'boolean | |
205 :group 'minibuffer) | |
206 | |
207 (defcustom minibuffer-electric-file-name-behavior t | |
208 "*If non-nil, slash and tilde in certain places cause immediate deletion. | |
209 These are the same places where this behavior would occur later on anyway, | |
210 in `substitute-in-file-name'." | |
211 :type 'boolean | |
212 :group 'minibuffer) | |
213 | |
214 ;; originally by Stig@hackvan.com | |
215 (defun minibuffer-electric-separator () | |
216 (interactive) | |
217 (let ((c last-command-char)) | |
218 (and minibuffer-electric-file-name-behavior | |
219 (eq c directory-sep-char) | |
220 (eq c (char-before (point))) | |
221 (not (save-excursion | |
222 (goto-char (point-min)) | |
223 (and (looking-at "/.+:~?[^/]*/.+") | |
224 (re-search-forward "^/.+:~?[^/]*" nil t) | |
225 (progn | |
226 (delete-region (point) (point-max)) | |
227 t)))) | |
228 (not (save-excursion | |
229 (goto-char (point-min)) | |
230 (and (looking-at ".+://[^/]*/.+") | |
231 (re-search-forward "^.+:/" nil t) | |
232 (progn | |
233 (delete-region (point) (point-max)) | |
234 t)))) | |
235 ;; permit `//hostname/path/to/file' | |
236 (not (eq (point) (1+ (point-min)))) | |
237 ;; permit `http://url/goes/here' | |
238 (or (not (eq ?: (char-after (- (point) 2)))) | |
239 (eq ?/ (char-after (point-min)))) | |
240 (delete-region (point-min) (point))) | |
241 (insert c))) | |
242 | |
243 (defun minibuffer-electric-tilde () | |
244 (interactive) | |
245 (and minibuffer-electric-file-name-behavior | |
246 (eq directory-sep-char (char-before (point))) | |
247 ;; permit URL's with //, for e.g. http://hostname/~user | |
248 (not (save-excursion (search-backward "//" nil t))) | |
249 (delete-region (point-min) (point))) | |
250 (insert ?~)) | |
251 | |
252 | |
253 (defvar read-file-name-map | |
254 (let ((map (make-sparse-keymap 'read-file-name-map))) | |
255 (set-keymap-parents map (list minibuffer-local-completion-map)) | |
256 (define-key map (vector directory-sep-char) 'minibuffer-electric-separator) | |
257 (define-key map "~" 'minibuffer-electric-tilde) | |
258 map | |
259 )) | |
260 | |
261 (defvar read-file-name-must-match-map | |
262 (let ((map (make-sparse-keymap 'read-file-name-map))) | |
263 (set-keymap-parents map (list minibuffer-local-must-match-map)) | |
264 (define-key map (vector directory-sep-char) 'minibuffer-electric-separator) | |
265 (define-key map "~" 'minibuffer-electric-tilde) | |
266 map | |
267 )) | |
268 | |
269 (defun minibuffer-keyboard-quit () | |
270 "Abort recursive edit. | |
271 If `zmacs-regions' is true, and the zmacs region is active in this buffer, | |
272 then this key deactivates the region without beeping." | |
273 (interactive) | |
2611 | 274 (if (region-active-p) |
428 | 275 ;; pseudo-zmacs compatibility: don't beep if this ^G is simply |
276 ;; deactivating the region. If it is inactive, beep. | |
277 nil | |
278 (abort-recursive-edit))) | |
279 | |
280 ;;;; Guts of minibuffer invocation | |
281 | |
282 ;;#### The only things remaining in C are | |
283 ;; "Vminibuf_prompt" and the display junk | |
284 ;; "minibuf_prompt_width" and "minibuf_prompt_pix_width" | |
285 ;; Also "active_frame", though I suspect I could already | |
286 ;; hack that in Lisp if I could make any sense of the | |
287 ;; complete mess of frame/frame code in XEmacs. | |
288 ;; Vminibuf_prompt could easily be made Lisp-bindable. | |
289 ;; I suspect that minibuf_prompt*_width are actually recomputed | |
290 ;; by redisplay as needed -- or could be arranged to be so -- | |
291 ;; and that there could be need for read-minibuffer-internal to | |
292 ;; save and restore them. | |
293 ;;#### The only other thing which read-from-minibuffer-internal does | |
294 ;; which we can't presently do in Lisp is move the frame cursor | |
295 ;; to the start of the minibuffer line as it returns. This is | |
296 ;; a rather nice touch and should be preserved -- probably by | |
297 ;; providing some Lisp-level mechanism (extension to cursor-in-echo-area ?) | |
298 ;; to effect it. | |
299 | |
300 | |
301 ;; Like reset_buffer in FSF's buffer.c | |
302 ;; (Except that kill-all-local-variables doesn't nuke 'permanent-local | |
303 ;; variables -- we preserve them, reset_buffer doesn't.) | |
304 (defun reset-buffer (buffer) | |
305 (with-current-buffer buffer | |
306 ;(if (fboundp 'unlock-buffer) (unlock-buffer)) | |
307 (kill-all-local-variables) | |
308 (setq buffer-read-only nil) | |
309 ;; don't let read only text yanked into the minibuffer | |
310 ;; permanently wedge it. | |
311 (make-local-variable 'inhibit-read-only) | |
312 (setq inhibit-read-only t) | |
313 (erase-buffer) | |
314 ;(setq default-directory nil) | |
315 (setq buffer-file-name nil) | |
316 (setq buffer-file-truename nil) | |
317 (set-buffer-modified-p nil) | |
318 (setq buffer-backed-up nil) | |
319 (setq buffer-auto-save-file-name nil) | |
320 (set-buffer-dedicated-frame buffer nil) | |
2021 | 321 (set-marker (mark-marker t buffer) nil) |
428 | 322 buffer)) |
323 | |
324 (defvar minibuffer-history-variable 'minibuffer-history | |
325 "History list symbol to add minibuffer values to. | |
326 Each minibuffer output is added with | |
327 (set minibuffer-history-variable | |
328 (cons STRING (symbol-value minibuffer-history-variable)))") | |
329 (defvar minibuffer-history-position) | |
330 | |
331 ;; Added by hniksic: | |
332 (defvar initial-minibuffer-history-position) | |
333 (defvar current-minibuffer-contents) | |
334 (defvar current-minibuffer-point) | |
335 | |
336 (defcustom minibuffer-history-minimum-string-length nil | |
337 "*If this variable is non-nil, a string will not be added to the | |
338 minibuffer history if its length is less than that value." | |
339 :type '(choice (const :tag "Any" nil) | |
340 integer) | |
341 :group 'minibuffer) | |
342 | |
510 | 343 (define-error 'input-error "Keyboard input error" 'io-error) |
428 | 344 |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
345 ((macro |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
346 . (lambda (read-from-minibuffer-definition) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
347 (nsublis |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
348 ;; `M-x doctor' makes (the interned) history a local variable, use an |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
349 ;; uninterned symbol here so we don't interact with it. |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
350 '((history . #:history)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
351 read-from-minibuffer-definition))) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
352 (defun read-from-minibuffer (prompt &optional initial-contents keymap |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
353 readp history abbrev-table default) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
354 "Read a string from the minibuffer, prompting with string PROMPT. |
428 | 355 If optional second arg INITIAL-CONTENTS is non-nil, it is a string |
356 to be inserted into the minibuffer before reading input. | |
357 If INITIAL-CONTENTS is (STRING . POSITION), the initial input | |
358 is STRING, but point is placed POSITION characters into the string. | |
359 Third arg KEYMAP is a keymap to use while reading; | |
360 if omitted or nil, the default is `minibuffer-local-map'. | |
361 If fourth arg READ is non-nil, then interpret the result as a lisp object | |
362 and return that object: | |
363 in other words, do `(car (read-from-string INPUT-STRING))' | |
364 Fifth arg HISTORY, if non-nil, specifies a history list | |
365 and optionally the initial position in the list. | |
366 It can be a symbol, which is the history list variable to use, | |
367 or it can be a cons cell (HISTVAR . HISTPOS). | |
368 In that case, HISTVAR is the history list variable to use, | |
369 and HISTPOS is the initial position (the position in the list | |
370 which INITIAL-CONTENTS corresponds to). | |
371 If HISTORY is `t', no history will be recorded. | |
372 Positions are counted starting from 1 at the beginning of the list. | |
373 Sixth arg ABBREV-TABLE, if non-nil, becomes the value of `local-abbrev-table' | |
374 in the minibuffer. | |
430 | 375 Seventh arg DEFAULT, if non-nil, will be returned when user enters |
376 an empty string. | |
428 | 377 |
444 | 378 See also the variable `completion-highlight-first-word-only' for |
379 control over completion display." | |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
380 (if (and (not enable-recursive-minibuffers) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
381 (> (minibuffer-depth) 0) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
382 (eq (selected-window) (minibuffer-window))) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
383 (error "Command attempted to use minibuffer while in minibuffer")) |
428 | 384 |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
385 (if (and minibuffer-max-depth |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
386 (> minibuffer-max-depth 0) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
387 (>= (minibuffer-depth) minibuffer-max-depth)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
388 (minibuffer-max-depth-exceeded)) |
428 | 389 |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
390 ;; catch this error before the poor user has typed something... |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
391 (if history |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
392 (if (symbolp history) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
393 (or (boundp history) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
394 (error "History list %S is unbound" history)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
395 (or (boundp (car history)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
396 (error "History list %S is unbound" (car history))))) |
428 | 397 |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
398 (if (noninteractive) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
399 (progn |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
400 ;; XEmacs in -batch mode calls minibuffer: print the prompt. |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
401 (message "%s" (gettext prompt)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
402 ;;#### force-output |
428 | 403 |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
404 ;;#### Should this even be falling though to the code below? |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
405 ;;#### How does this stuff work now, anyway? |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
406 )) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
407 (let* ((dir default-directory) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
408 (owindow (selected-window)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
409 (oframe (selected-frame)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
410 (window (minibuffer-window)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
411 (buffer (get-buffer-create (format " *Minibuf-%d*" |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
412 (minibuffer-depth)))) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
413 (frame (window-frame window)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
414 (mconfig (if (eq frame (selected-frame)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
415 nil (current-window-configuration frame))) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
416 (oconfig (current-window-configuration)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
417 (minibuffer-default default)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
418 (unwind-protect |
428 | 419 (progn |
420 (set-buffer (reset-buffer buffer)) | |
421 (setq default-directory dir) | |
422 (make-local-variable 'print-escape-newlines) | |
423 (setq print-escape-newlines t) | |
424 (make-local-variable 'current-minibuffer-contents) | |
425 (make-local-variable 'current-minibuffer-point) | |
426 (make-local-variable 'initial-minibuffer-history-position) | |
427 (setq current-minibuffer-contents "" | |
428 current-minibuffer-point 1) | |
429 (if (not minibuffer-smart-completion-tracking-behavior) | |
430 nil | |
431 (make-local-variable 'mode-motion-hook) | |
432 (or mode-motion-hook | |
433 ;;####disgusting | |
434 (setq mode-motion-hook 'minibuffer-smart-mouse-tracker)) | |
435 (make-local-variable 'mouse-track-click-hook) | |
436 (add-hook 'mouse-track-click-hook | |
437 'minibuffer-smart-maybe-select-highlighted-completion)) | |
438 (set-window-buffer window buffer) | |
439 (select-window window) | |
440 (set-window-hscroll window 0) | |
441 (buffer-enable-undo buffer) | |
442 (message nil) | |
443 (if initial-contents | |
444 (if (consp initial-contents) | |
445 (progn | |
446 (insert (car initial-contents)) | |
447 (goto-char (1+ (cdr initial-contents))) | |
448 (setq current-minibuffer-contents (car initial-contents) | |
449 current-minibuffer-point (cdr initial-contents))) | |
450 (insert initial-contents) | |
451 (setq current-minibuffer-contents initial-contents | |
452 current-minibuffer-point (point)))) | |
453 (use-local-map (help-keymap-with-help-key | |
454 (or keymap minibuffer-local-map) | |
455 minibuffer-help-form)) | |
456 (let ((mouse-grabbed-buffer | |
457 (and minibuffer-smart-completion-tracking-behavior | |
458 (current-buffer))) | |
459 (current-prefix-arg current-prefix-arg) | |
460 ;; (help-form minibuffer-help-form) | |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
461 (minibuffer-history-variable (cond ((not history) |
428 | 462 'minibuffer-history) |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
463 ((consp history) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
464 (car history)) |
428 | 465 (t |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
466 history))) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
467 (minibuffer-history-position (cond ((consp history) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
468 (cdr history)) |
428 | 469 (t |
470 0))) | |
471 (minibuffer-scroll-window owindow)) | |
472 (setq initial-minibuffer-history-position | |
473 minibuffer-history-position) | |
474 (if abbrev-table | |
475 (setq local-abbrev-table abbrev-table | |
476 abbrev-mode t)) | |
477 ;; This is now run from read-minibuffer-internal | |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
478 ;(if minibuffer-setup-hook |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
479 ; (run-hooks 'minibuffer-setup-hook)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
480 ;(message nil) |
428 | 481 (if (eq 't |
482 (catch 'exit | |
483 (if (> (recursion-depth) (minibuffer-depth)) | |
484 (let ((standard-output t) | |
485 (standard-input t)) | |
486 (read-minibuffer-internal prompt)) | |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
487 (read-minibuffer-internal prompt)))) |
428 | 488 ;; Translate an "abort" (throw 'exit 't) |
489 ;; into a real quit | |
490 (signal 'quit '()) | |
491 ;; return value | |
492 (let* ((val (progn (set-buffer buffer) | |
493 (if minibuffer-exit-hook | |
494 (run-hooks 'minibuffer-exit-hook)) | |
430 | 495 (if (and (eq (char-after (point-min)) nil) |
496 default) | |
497 default | |
498 (buffer-string)))) | |
499 (histval (if (and default (string= val "")) | |
500 default | |
501 val)) | |
428 | 502 (err nil)) |
503 (if readp | |
504 (condition-case e | |
505 (let ((v (read-from-string val))) | |
506 (if (< (cdr v) (length val)) | |
507 (save-match-data | |
508 (or (string-match "[ \t\n]*\\'" val (cdr v)) | |
509 (error "Trailing garbage following expression")))) | |
510 (setq v (car v)) | |
511 ;; total total kludge | |
512 (if (stringp v) (setq v (list 'quote v))) | |
513 (setq val v)) | |
514 (end-of-file | |
515 (setq err | |
516 '(input-error "End of input before end of expression"))) | |
517 (error (setq err e)))) | |
518 ;; Add the value to the appropriate history list unless | |
519 ;; it's already the most recent element, or it's only | |
520 ;; two characters long. | |
521 (if (and (symbolp minibuffer-history-variable) | |
522 (boundp minibuffer-history-variable)) | |
523 (let ((list (symbol-value minibuffer-history-variable))) | |
524 (or (eq list t) | |
525 (null val) | |
526 (and list (equal histval (car list))) | |
527 (and (stringp val) | |
528 minibuffer-history-minimum-string-length | |
529 (< (length val) | |
530 minibuffer-history-minimum-string-length)) | |
531 (set minibuffer-history-variable | |
532 (if minibuffer-history-uniquify | |
533 (cons histval (remove histval list)) | |
534 (cons histval list)))))) | |
535 (if err (signal (car err) (cdr err))) | |
536 val)))) | |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
537 ;; stupid display code requires this for some reason |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
538 (set-buffer buffer) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
539 (buffer-disable-undo buffer) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
540 (setq buffer-read-only nil) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
541 (erase-buffer) |
428 | 542 |
4806
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
543 ;; restore frame configurations |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
544 (if (and mconfig (frame-live-p oframe) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
545 (eq frame (selected-frame))) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
546 ;; if we changed frames (due to surrogate minibuffer), |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
547 ;; and we're still on the new frame, go back to the old one. |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
548 (select-frame oframe)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
549 (if mconfig (set-window-configuration mconfig)) |
fd36a980d701
Use uninterned symbols in various information-hiding contexts.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4734
diff
changeset
|
550 (set-window-configuration oconfig))))) |
428 | 551 |
552 (defun minibuffer-max-depth-exceeded () | |
553 ;; | |
554 ;; This signals an error if an Nth minibuffer is invoked while N-1 are | |
555 ;; already active, whether the minibuffer window is selected or not. | |
556 ;; Since, under X, it's easy to jump out of the minibuffer (by doing M-x, | |
557 ;; getting distracted, and clicking elsewhere) many many novice users have | |
558 ;; had the problem of having multiple minibuffers build up, even to the | |
559 ;; point of exceeding max-lisp-eval-depth. Since the variable | |
560 ;; enable-recursive-minibuffers historically/crockishly is only consulted | |
561 ;; when the minibuffer is currently active (like typing M-x M-x) it doesn't | |
562 ;; help in this situation. | |
563 ;; | |
564 ;; This routine also offers to edit .emacs for you to get rid of this | |
565 ;; complaint, like `disabled' commands do, since it's likely that non-novice | |
566 ;; users will be annoyed by this change, so we give them an easy way to get | |
567 ;; rid of it forever. | |
568 ;; | |
569 (beep t 'minibuffer-limit-exceeded) | |
570 (message | |
571 "Minibuffer already active: abort it with `^]', enable new one with `n': ") | |
572 (let ((char (let ((cursor-in-echo-area t)) ; #### doesn't always work?? | |
573 (read-char)))) | |
574 (cond | |
575 ((eq char ?n) | |
576 (cond | |
577 ((y-or-n-p "Enable recursive minibuffers for other sessions too? ") | |
578 ;; This is completely disgusting, but it's basically what novice.el | |
579 ;; does. This kind of thing should be generalized. | |
580 (setq minibuffer-max-depth nil) | |
581 (save-excursion | |
582 (set-buffer | |
583 (find-file-noselect | |
584 (substitute-in-file-name custom-file))) | |
585 (goto-char (point-min)) | |
586 (if (re-search-forward | |
587 "^(setq minibuffer-max-depth \\([0-9]+\\|'?nil\\|'?()\\))\n" | |
588 nil t) | |
589 (delete-region (match-beginning 0 ) (match-end 0)) | |
590 ;; Must have been disabled by default. | |
591 (goto-char (point-max))) | |
592 (insert"\n(setq minibuffer-max-depth nil)\n") | |
593 (save-buffer)) | |
594 (message "Multiple minibuffers enabled") | |
595 (sit-for 1)))) | |
596 ((eq char ?) | |
597 (abort-recursive-edit)) | |
598 (t | |
599 (error "Minibuffer already active"))))) | |
600 | |
601 | |
602 ;;;; Guts of minibuffer completion | |
603 | |
604 | |
605 ;; Used by minibuffer-do-completion | |
442 | 606 (defvar last-exact-completion nil) |
428 | 607 |
608 (defun temp-minibuffer-message (m) | |
609 (let ((savemax (point-max))) | |
610 (save-excursion | |
611 (goto-char (point-max)) | |
612 (message nil) | |
613 (insert m)) | |
614 (let ((inhibit-quit t)) | |
615 (sit-for 2) | |
616 (delete-region savemax (point-max)) | |
617 ;; If the user types a ^G while we're in sit-for, then quit-flag | |
618 ;; gets set. In this case, we want that ^G to be interpreted | |
619 ;; as a normal character, and act just like typeahead. | |
620 (if (and quit-flag (not unread-command-event)) | |
621 (setq unread-command-event (character-to-event (quit-char)) | |
622 quit-flag nil))))) | |
623 | |
624 | |
625 ;; Determines whether buffer-string is an exact completion | |
626 (defun exact-minibuffer-completion-p (buffer-string) | |
627 (cond ((not minibuffer-completion-table) | |
628 ;; Empty alist | |
629 nil) | |
630 ((vectorp minibuffer-completion-table) | |
631 (let ((tem (intern-soft buffer-string | |
632 minibuffer-completion-table))) | |
633 (if (or tem | |
634 (and (string-equal buffer-string "nil") | |
635 ;; intern-soft loses for 'nil | |
636 (catch 'found | |
637 (mapatoms #'(lambda (s) | |
638 (if (string-equal | |
639 (symbol-name s) | |
640 buffer-string) | |
641 (throw 'found t))) | |
642 minibuffer-completion-table) | |
643 nil))) | |
644 (if minibuffer-completion-predicate | |
645 (funcall minibuffer-completion-predicate | |
646 tem) | |
647 t) | |
648 nil))) | |
649 ((and (consp minibuffer-completion-table) | |
650 ;;#### Emacs-Lisp truly sucks! | |
651 ;; lambda, autoload, etc | |
652 (not (symbolp (car minibuffer-completion-table)))) | |
653 (if (not completion-ignore-case) | |
654 (assoc buffer-string minibuffer-completion-table) | |
655 (let ((s (upcase buffer-string)) | |
656 (tail minibuffer-completion-table) | |
657 tem) | |
658 (while tail | |
659 (setq tem (car (car tail))) | |
660 (if (or (equal tem buffer-string) | |
661 (equal tem s) | |
662 (if tem (equal (upcase tem) s))) | |
663 (setq s 'win | |
664 tail nil) ;exit | |
665 (setq tail (cdr tail)))) | |
666 (eq s 'win)))) | |
667 (t | |
668 (funcall minibuffer-completion-table | |
669 buffer-string | |
670 minibuffer-completion-predicate | |
671 'lambda))) | |
672 ) | |
673 | |
674 ;; 0 'none no possible completion | |
675 ;; 1 'unique was already an exact and unique completion | |
676 ;; 3 'exact was already an exact (but nonunique) completion | |
677 ;; NOT USED 'completed-exact-unique completed to an exact and completion | |
678 ;; 4 'completed-exact completed to an exact (but nonunique) completion | |
679 ;; 5 'completed some completion happened | |
680 ;; 6 'uncompleted no completion happened | |
681 (defun minibuffer-do-completion-1 (buffer-string completion) | |
682 (cond ((not completion) | |
683 'none) | |
684 ((eq completion t) | |
685 ;; exact and unique match | |
686 'unique) | |
687 (t | |
688 ;; It did find a match. Do we match some possibility exactly now? | |
689 (let ((completedp (not (string-equal completion buffer-string)))) | |
690 (if completedp | |
691 (progn | |
692 ;; Some completion happened | |
693 (erase-buffer) | |
694 (insert completion) | |
695 (setq buffer-string completion))) | |
696 (if (exact-minibuffer-completion-p buffer-string) | |
697 ;; An exact completion was possible | |
698 (if completedp | |
699 ;; Since no callers need to know the difference, don't bother | |
700 ;; with this (potentially expensive) discrimination. | |
701 ;; (if (eq (try-completion completion | |
702 ;; minibuffer-completion-table | |
703 ;; minibuffer-completion-predicate) | |
704 ;; 't) | |
705 ;; 'completed-exact-unique | |
706 'completed-exact | |
707 ;; ) | |
708 'exact) | |
709 ;; Not an exact match | |
710 (if completedp | |
711 'completed | |
712 'uncompleted)))))) | |
713 | |
714 | |
715 (defun minibuffer-do-completion (buffer-string) | |
716 (let* ((completion (try-completion buffer-string | |
717 minibuffer-completion-table | |
718 minibuffer-completion-predicate)) | |
719 (status (minibuffer-do-completion-1 buffer-string completion)) | |
720 (last last-exact-completion)) | |
721 (setq last-exact-completion nil) | |
722 (cond ((eq status 'none) | |
723 ;; No completions | |
724 (ding nil 'no-completion) | |
725 (temp-minibuffer-message " [No match]")) | |
726 ((eq status 'unique) | |
727 ) | |
728 (t | |
729 ;; It did find a match. Do we match some possibility exactly now? | |
730 (if (not (string-equal completion buffer-string)) | |
731 (progn | |
732 ;; Some completion happened | |
733 (erase-buffer) | |
734 (insert completion) | |
735 (setq buffer-string completion))) | |
736 (cond ((eq status 'exact) | |
737 ;; If the last exact completion and this one were | |
738 ;; the same, it means we've already given a | |
739 ;; "Complete but not unique" message and that the | |
740 ;; user's hit TAB again, so now we give help. | |
741 (setq last-exact-completion completion) | |
742 (if (equal buffer-string last) | |
743 (minibuffer-completion-help))) | |
744 ((eq status 'uncompleted) | |
745 (if completion-auto-help | |
746 (minibuffer-completion-help) | |
747 (temp-minibuffer-message " [Next char not unique]"))) | |
748 (t | |
749 nil)))) | |
750 status)) | |
751 | |
752 | |
753 ;;;; completing-read | |
754 | |
755 (defun completing-read (prompt table | |
756 &optional predicate require-match | |
757 initial-contents history default) | |
758 "Read a string in the minibuffer, with completion. | |
863 | 759 |
428 | 760 PROMPT is a string to prompt with; normally it ends in a colon and a space. |
761 TABLE is an alist whose elements' cars are strings, or an obarray. | |
863 | 762 TABLE can also be a function which does the completion itself. |
428 | 763 PREDICATE limits completion to a subset of TABLE. |
765 | 764 See `try-completion' and `all-completions' for more details |
765 on completion, TABLE, and PREDICATE. | |
766 | |
428 | 767 If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless |
765 | 768 the input is (or completes to) an element of TABLE or is null. |
769 If it is also not t, Return does not exit if it does non-null completion. | |
428 | 770 If INITIAL-CONTENTS is non-nil, insert it in the minibuffer initially. |
771 If it is (STRING . POSITION), the initial input | |
772 is STRING, but point is placed POSITION characters into the string. | |
765 | 773 |
428 | 774 HISTORY, if non-nil, specifies a history list |
775 and optionally the initial position in the list. | |
776 It can be a symbol, which is the history list variable to use, | |
777 or it can be a cons cell (HISTVAR . HISTPOS). | |
778 In that case, HISTVAR is the history list variable to use, | |
779 and HISTPOS is the initial position (the position in the list | |
780 which INITIAL-CONTENTS corresponds to). | |
781 If HISTORY is `t', no history will be recorded. | |
782 Positions are counted starting from 1 at the beginning of the list. | |
765 | 783 DEFAULT, if non-nil, will be returned when the user enters an empty |
784 string. | |
785 | |
428 | 786 Completion ignores case if the ambient value of |
787 `completion-ignore-case' is non-nil." | |
788 (let ((minibuffer-completion-table table) | |
789 (minibuffer-completion-predicate predicate) | |
790 (minibuffer-completion-confirm (if (eq require-match 't) nil t)) | |
791 (last-exact-completion nil) | |
792 ret) | |
793 (setq ret (read-from-minibuffer prompt | |
794 initial-contents | |
795 (if (not require-match) | |
796 minibuffer-local-completion-map | |
797 minibuffer-local-must-match-map) | |
798 nil | |
430 | 799 history |
800 nil | |
801 default)) | |
428 | 802 (if (and (string= ret "") |
803 default) | |
804 default | |
805 ret))) | |
806 | |
807 | |
808 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
809 ;;;; Minibuffer completion commands ;;;; | |
810 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
811 | |
812 | |
813 (defun minibuffer-complete () | |
814 "Complete the minibuffer contents as far as possible. | |
815 Return nil if there is no valid completion, else t. | |
816 If no characters can be completed, display a list of possible completions. | |
817 If you repeat this command after it displayed such a list, | |
818 scroll the window of possible completions." | |
819 (interactive) | |
820 ;; If the previous command was not this, then mark the completion | |
821 ;; buffer obsolete. | |
822 (or (eq last-command this-command) | |
823 (setq minibuffer-scroll-window nil)) | |
824 (let ((window minibuffer-scroll-window)) | |
825 (if (and window (windowp window) (window-buffer window) | |
826 (buffer-name (window-buffer window))) | |
827 ;; If there's a fresh completion window with a live buffer | |
828 ;; and this command is repeated, scroll that window. | |
829 (let ((obuf (current-buffer))) | |
830 (unwind-protect | |
831 (progn | |
832 (set-buffer (window-buffer window)) | |
833 (if (pos-visible-in-window-p (point-max) window) | |
834 ;; If end is in view, scroll up to the beginning. | |
835 (set-window-start window (point-min)) | |
836 ;; Else scroll down one frame. | |
837 (scroll-other-window))) | |
838 (set-buffer obuf)) | |
839 nil) | |
840 (let ((status (minibuffer-do-completion (buffer-string)))) | |
841 (if (eq status 'none) | |
842 nil | |
843 (progn | |
844 (cond ((eq status 'unique) | |
845 (temp-minibuffer-message | |
846 " [Sole completion]")) | |
847 ((eq status 'exact) | |
848 (temp-minibuffer-message | |
849 " [Complete, but not unique]"))) | |
850 t)))))) | |
851 | |
852 | |
853 (defun minibuffer-complete-and-exit () | |
854 "Complete the minibuffer contents, and maybe exit. | |
855 Exit if the name is valid with no completion needed. | |
856 If name was completed to a valid match, | |
857 a repetition of this command will exit." | |
858 (interactive) | |
859 (if (= (point-min) (point-max)) | |
860 ;; Crockishly allow user to specify null string | |
861 (throw 'exit nil)) | |
862 (let ((buffer-string (buffer-string))) | |
863 ;; Short-cut -- don't call minibuffer-do-completion if we already | |
864 ;; have an (possibly nonunique) exact completion. | |
865 (if (exact-minibuffer-completion-p buffer-string) | |
866 (throw 'exit nil)) | |
867 (let ((status (minibuffer-do-completion buffer-string))) | |
868 (if (or (eq status 'unique) | |
869 (eq status 'exact) | |
870 (if (or (eq status 'completed-exact) | |
871 (eq status 'completed-exact-unique)) | |
872 (if minibuffer-completion-confirm | |
873 (progn (temp-minibuffer-message " [Confirm]") | |
874 nil) | |
875 t))) | |
876 (throw 'exit nil))))) | |
877 | |
878 | |
879 (defun self-insert-and-exit () | |
880 "Terminate minibuffer input." | |
881 (interactive) | |
882 (self-insert-command 1) | |
883 (throw 'exit nil)) | |
884 | |
885 (defun exit-minibuffer () | |
886 "Terminate this minibuffer argument. | |
887 If minibuffer-confirm-incomplete is true, and we are in a completing-read | |
888 of some kind, and the contents of the minibuffer is not an existing | |
889 completion, requires an additional RET before the minibuffer will be exited | |
890 \(assuming that RET was the character that invoked this command: | |
891 the character in question must be typed again)." | |
892 (interactive) | |
893 (if (not minibuffer-confirm-incomplete) | |
894 (throw 'exit nil)) | |
895 (let ((buffer-string (buffer-string))) | |
896 (if (exact-minibuffer-completion-p buffer-string) | |
897 (throw 'exit nil)) | |
898 (let ((completion (if (not minibuffer-completion-table) | |
899 t | |
900 (try-completion buffer-string | |
901 minibuffer-completion-table | |
902 minibuffer-completion-predicate)))) | |
903 (if (or (eq completion 't) | |
904 ;; Crockishly allow user to specify null string | |
905 (string-equal buffer-string "")) | |
906 (throw 'exit nil)) | |
907 (if completion ;; rewritten for I18N3 snarfing | |
908 (temp-minibuffer-message " [incomplete; confirm]") | |
909 (temp-minibuffer-message " [no completions; confirm]")) | |
910 (let ((event (let ((inhibit-quit t)) | |
911 (prog1 | |
912 (next-command-event) | |
913 (setq quit-flag nil))))) | |
914 (cond ((equal event last-command-event) | |
915 (throw 'exit nil)) | |
916 ((equal (quit-char) (event-to-character event)) | |
917 ;; Minibuffer abort. | |
918 (throw 'exit t))) | |
919 (dispatch-event event))))) | |
920 | |
921 ;;;; minibuffer-complete-word | |
922 | |
923 | |
924 ;;;#### I think I have done this correctly; it certainly is simpler | |
925 ;;;#### than what the C code seemed to be trying to do. | |
926 (defun minibuffer-complete-word () | |
927 "Complete the minibuffer contents at most a single word. | |
928 After one word is completed as much as possible, a space or hyphen | |
929 is added, provided that matches some possible completion. | |
930 Return nil if there is no valid completion, else t." | |
931 (interactive) | |
932 (let* ((buffer-string (buffer-string)) | |
933 (completion (try-completion buffer-string | |
934 minibuffer-completion-table | |
935 minibuffer-completion-predicate)) | |
936 (status (minibuffer-do-completion-1 buffer-string completion))) | |
937 (cond ((eq status 'none) | |
938 (ding nil 'no-completion) | |
939 (temp-minibuffer-message " [No match]") | |
940 nil) | |
941 ((eq status 'unique) | |
942 ;; New message, only in this new Lisp code | |
943 (temp-minibuffer-message " [Sole completion]") | |
944 t) | |
945 (t | |
946 (cond ((or (eq status 'uncompleted) | |
947 (eq status 'exact)) | |
948 (let ((foo #'(lambda (s) | |
949 (condition-case nil | |
950 (if (try-completion | |
951 (concat buffer-string s) | |
952 minibuffer-completion-table | |
953 minibuffer-completion-predicate) | |
954 (progn | |
955 (goto-char (point-max)) | |
956 (insert s) | |
957 t) | |
958 nil) | |
959 (error nil)))) | |
960 (char last-command-char)) | |
961 ;; Try to complete by adding a word-delimiter | |
962 (or (and (characterp char) (> char 0) | |
963 (funcall foo (char-to-string char))) | |
964 (and (not (eq char ?\ )) | |
965 (funcall foo " ")) | |
966 (and (not (eq char ?\-)) | |
967 (funcall foo "-")) | |
968 (progn | |
969 (if completion-auto-help | |
970 (minibuffer-completion-help) | |
971 ;; New message, only in this new Lisp code | |
972 ;; rewritten for I18N3 snarfing | |
973 (if (eq status 'exact) | |
974 (temp-minibuffer-message | |
975 " [Complete, but not unique]") | |
976 (temp-minibuffer-message " [Ambiguous]"))) | |
977 nil)))) | |
978 (t | |
979 (erase-buffer) | |
980 (insert completion) | |
981 ;; First word-break in stuff found by completion | |
982 (goto-char (point-min)) | |
983 (let ((len (length buffer-string)) | |
984 n) | |
985 (if (and (< len (length completion)) | |
986 (catch 'match | |
987 (setq n 0) | |
988 (while (< n len) | |
989 (if (char-equal | |
990 (upcase (aref buffer-string n)) | |
991 (upcase (aref completion n))) | |
992 (setq n (1+ n)) | |
993 (throw 'match nil))) | |
994 t) | |
995 (progn | |
996 (goto-char (point-min)) | |
997 (forward-char len) | |
998 (re-search-forward "\\W" nil t))) | |
999 (delete-region (point) (point-max)) | |
1000 (goto-char (point-max)))) | |
1001 t)))))) | |
1002 | |
1003 | |
1004 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
1005 ;;;; "Smart minibuffer" hackery ;;;; | |
1006 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
1007 | |
1008 ;;; ("Kludgy minibuffer hackery" is perhaps a better name) | |
1009 | |
1010 ;; This works by setting `mouse-grabbed-buffer' to the minibuffer, | |
1011 ;; defining button2 in the minibuffer keymap to | |
1012 ;; `minibuffer-smart-select-highlighted-completion', and setting the | |
1013 ;; mode-motion-hook of the minibuffer to `minibuffer-mouse-tracker'. | |
1014 ;; By setting `mouse-grabbed-buffer', the minibuffer's keymap and | |
1015 ;; mode-motion-hook apply (for mouse motion and presses) no matter | |
1016 ;; what buffer the mouse is over. Then, `minibuffer-mouse-tracker' | |
1017 ;; examines the text under the mouse looking for something that looks | |
1018 ;; like a completion, and causes it to be highlighted, and | |
1019 ;; `minibuffer-smart-select-highlighted-completion' looks for a | |
1020 ;; flagged completion under the mouse and inserts it. This has the | |
1021 ;; following advantages: | |
1022 ;; | |
1023 ;; -- filenames and such in any buffer can be inserted by clicking, | |
1024 ;; not just completions | |
1025 ;; | |
1026 ;; but the following disadvantages: | |
1027 ;; | |
1028 ;; -- unless you're aware of the "filename in any buffer" feature, | |
1029 ;; the fact that strings in arbitrary buffers get highlighted appears | |
1030 ;; as a bug | |
1031 ;; -- mouse motion can cause ange-ftp actions -- bad bad bad. | |
1032 ;; | |
1033 ;; There's some hackery in minibuffer-mouse-tracker to try to avoid the | |
1034 ;; ange-ftp stuff, but it doesn't work. | |
1035 ;; | |
1036 | |
1037 (defcustom minibuffer-smart-completion-tracking-behavior nil | |
1038 "*If non-nil, look for completions under mouse in all buffers. | |
1039 This allows you to click on something that looks like a completion | |
1040 and have it selected, regardless of what buffer it is in. | |
1041 | |
1042 This is not enabled by default because | |
1043 | |
1044 -- The \"mysterious\" highlighting in normal buffers is confusing to | |
1045 people not expecting it, and looks like a bug | |
1046 -- If ange-ftp is enabled, this tracking sometimes causes ange-ftp | |
1047 action as a result of mouse motion, which is *bad bad bad*. | |
1048 Hopefully this bug will be fixed at some point." | |
1049 :type 'boolean | |
1050 :group 'minibuffer) | |
1051 | |
1052 (defun minibuffer-smart-mouse-tracker (event) | |
1053 ;; Used as the mode-motion-hook of the minibuffer window, which is the | |
1054 ;; value of `mouse-grabbed-buffer' while the minibuffer is active. If | |
1055 ;; the word under the mouse is a valid minibuffer completion, then it | |
1056 ;; is highlighted. | |
1057 ;; | |
1058 ;; We do some special voodoo when we're reading a pathname, because | |
1059 ;; the way filename completion works is funny. Possibly there's some | |
1060 ;; more general way this could be dealt with... | |
1061 ;; | |
1062 ;; We do some further voodoo when reading a pathname that is an | |
1063 ;; ange-ftp or efs path, because causing FTP activity as a result of | |
1064 ;; mouse motion is a really bad time. | |
1065 ;; | |
1066 (and minibuffer-smart-completion-tracking-behavior | |
1067 (event-point event) | |
1068 ;; avoid conflict with display-completion-list extents | |
1069 (not (extent-at (event-point event) | |
1070 (event-buffer event) | |
1071 'list-mode-item)) | |
1072 (let ((filename-kludge-p (eq minibuffer-completion-table | |
1073 'read-file-name-internal))) | |
1074 (mode-motion-highlight-internal | |
1075 event | |
1076 #'(lambda () (default-mouse-track-beginning-of-word | |
1077 (if filename-kludge-p 'nonwhite t))) | |
1078 #'(lambda () | |
1079 (let ((p (point)) | |
1080 (string "")) | |
1081 (default-mouse-track-end-of-word | |
1082 (if filename-kludge-p 'nonwhite t)) | |
1083 (if (and (/= p (point)) minibuffer-completion-table) | |
1084 (setq string (buffer-substring p (point)))) | |
1085 (if (string-match "\\`[ \t\n]*\\'" string) | |
1086 (goto-char p) | |
1087 (if filename-kludge-p | |
1088 (setq string (minibuffer-smart-select-kludge-filename | |
1089 string))) | |
1090 ;; try-completion bogusly returns a string even when | |
1091 ;; that string is complete if that string is also a | |
1092 ;; prefix for other completions. This means that we | |
1093 ;; can't just do the obvious thing, (eq t | |
1094 ;; (try-completion ...)). | |
1095 (let (comp) | |
1096 (if (and filename-kludge-p | |
1097 ;; #### evil evil evil evil | |
1098 (or (and (fboundp 'ange-ftp-ftp-path) | |
502 | 1099 (declare-fboundp |
1100 (ange-ftp-ftp-path string))) | |
428 | 1101 (and (fboundp 'efs-ftp-path) |
502 | 1102 (declare-fboundp |
1103 (efs-ftp-path string))))) | |
428 | 1104 (setq comp t) |
1105 (setq comp | |
1106 (try-completion string | |
1107 minibuffer-completion-table | |
1108 minibuffer-completion-predicate))) | |
1109 (or (eq comp t) | |
1110 (and (equal comp string) | |
1111 (or (null minibuffer-completion-predicate) | |
1112 (stringp | |
1113 minibuffer-completion-predicate) ; ??? | |
1114 (funcall minibuffer-completion-predicate | |
1115 (if (vectorp | |
1116 minibuffer-completion-table) | |
1117 (intern-soft | |
1118 string | |
1119 minibuffer-completion-table) | |
1120 string)))) | |
1121 (goto-char p)))))))))) | |
1122 | |
1123 (defun minibuffer-smart-select-kludge-filename (string) | |
1124 (save-excursion | |
1125 (set-buffer mouse-grabbed-buffer) ; the minibuf | |
1126 (let ((kludge-string (concat (buffer-string) string))) | |
1127 (if (or (and (fboundp 'ange-ftp-ftp-path) | |
502 | 1128 (declare-fboundp (ange-ftp-ftp-path kludge-string))) |
1129 (and (fboundp 'efs-ftp-path) | |
1130 (declare-fboundp (efs-ftp-path kludge-string)))) | |
1131 ;; #### evil evil evil, but more so. | |
1132 string | |
1133 (append-expand-filename (buffer-string) string))))) | |
428 | 1134 |
1135 (defun minibuffer-smart-select-highlighted-completion (event) | |
1136 "Select the highlighted text under the mouse as a minibuffer response. | |
1137 When the minibuffer is being used to prompt the user for a completion, | |
1138 any valid completions which are visible on the frame will highlight | |
1139 when the mouse moves over them. Clicking \\<minibuffer-local-map>\ | |
1140 \\[minibuffer-smart-select-highlighted-completion] will select the | |
1141 highlighted completion under the mouse. | |
1142 | |
1143 If the mouse is clicked while not over a highlighted completion, | |
1144 then the global binding of \\[minibuffer-smart-select-highlighted-completion] \ | |
1145 will be executed instead. In this\nway you can get at the normal global \ | |
1146 behavior of \\[minibuffer-smart-select-highlighted-completion] as well as | |
1147 the special minibuffer behavior." | |
1148 (interactive "e") | |
1149 (if minibuffer-smart-completion-tracking-behavior | |
1150 (minibuffer-smart-select-highlighted-completion-1 event t) | |
1151 (let ((command (lookup-key global-map | |
1152 (vector current-mouse-event)))) | |
1153 (if command (call-interactively command))))) | |
1154 | |
1155 (defun minibuffer-smart-select-highlighted-completion-1 (event global-p) | |
1156 (let* ((filename-kludge-p (eq minibuffer-completion-table | |
1157 'read-file-name-internal)) | |
1158 completion | |
1159 command-p | |
1160 (evpoint (event-point event)) | |
1161 (evextent (and evpoint (extent-at evpoint (event-buffer event) | |
1162 'list-mode-item)))) | |
1163 (if evextent | |
1164 ;; avoid conflict with display-completion-list extents. | |
1165 ;; if we find one, do that behavior instead. | |
1166 (list-mode-item-selected-1 evextent event) | |
1167 (save-excursion | |
1168 (let* ((buffer (window-buffer (event-window event))) | |
1169 (p (event-point event)) | |
1170 (extent (and p (extent-at p buffer 'mouse-face)))) | |
1171 (set-buffer buffer) | |
1172 (if (not (and (extent-live-p extent) | |
1173 (eq (extent-object extent) (current-buffer)) | |
1174 (not (extent-detached-p extent)))) | |
1175 (setq command-p t) | |
1176 ;; ...else user has selected a highlighted completion. | |
1177 (setq completion | |
1178 (buffer-substring (extent-start-position extent) | |
1179 (extent-end-position extent))) | |
1180 (if filename-kludge-p | |
1181 (setq completion (minibuffer-smart-select-kludge-filename | |
1182 completion))) | |
1183 ;; remove the extent so that it's not hanging around in | |
1184 ;; *Completions* | |
1185 (detach-extent extent) | |
1186 (set-buffer mouse-grabbed-buffer) | |
1187 (erase-buffer) | |
1188 (insert completion)))) | |
1189 ;; we need to execute the command or do the throw outside of the | |
1190 ;; save-excursion. | |
1191 (cond ((and command-p global-p) | |
1192 (let ((command (lookup-key global-map | |
1193 (vector current-mouse-event)))) | |
1194 (if command | |
1195 (call-interactively command) | |
1196 (if minibuffer-completion-table | |
1197 (error | |
1198 "Highlighted words are valid completions. You may select one.") | |
1199 (error "no completions"))))) | |
1200 ((not command-p) | |
1201 ;; things get confused if the minibuffer is terminated while | |
1202 ;; not selected. | |
1203 (select-window (minibuffer-window)) | |
1204 (if (and filename-kludge-p (file-directory-p completion)) | |
1205 ;; if the user clicked middle on a directory name, display the | |
1206 ;; files in that directory. | |
1207 (progn | |
1208 (goto-char (point-max)) | |
1209 (minibuffer-completion-help)) | |
1210 ;; otherwise, terminate input | |
1211 (throw 'exit nil))))))) | |
1212 | |
1213 (defun minibuffer-smart-maybe-select-highlighted-completion | |
1214 (event &optional click-count) | |
444 | 1215 "Like `minibuffer-smart-select-highlighted-completion' but does nothing if |
428 | 1216 there is no completion (as opposed to executing the global binding). Useful |
1217 as the value of `mouse-track-click-hook'." | |
1218 (interactive "e") | |
1219 (minibuffer-smart-select-highlighted-completion-1 event nil)) | |
1220 | |
1221 (define-key minibuffer-local-map 'button2 | |
1222 'minibuffer-smart-select-highlighted-completion) | |
1223 | |
1224 | |
1225 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
1226 ;;;; Minibuffer History ;;;; | |
1227 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
1228 | |
1229 (defvar minibuffer-history '() | |
1230 "Default minibuffer history list. | |
1231 This is used for all minibuffer input except when an alternate history | |
1232 list is specified.") | |
1233 | |
1234 ;; Some other history lists: | |
1235 ;; | |
1236 (defvar minibuffer-history-search-history '()) | |
1237 (defvar function-history '()) | |
1238 (defvar variable-history '()) | |
1239 (defvar buffer-history '()) | |
1240 (defvar shell-command-history '()) | |
1241 (defvar file-name-history '()) | |
1242 | |
1243 (defvar read-expression-history nil) | |
1244 | |
1245 (defvar minibuffer-history-sexp-flag nil ;weird FSF Emacs kludge | |
1246 "Non-nil when doing history operations on `command-history'. | |
1247 More generally, indicates that the history list being acted on | |
1248 contains expressions rather than strings.") | |
1249 | |
1250 (defun previous-matching-history-element (regexp n) | |
1251 "Find the previous history element that matches REGEXP. | |
1252 \(Previous history elements refer to earlier actions.) | |
1253 With prefix argument N, search for Nth previous match. | |
1254 If N is negative, find the next or Nth next match." | |
1255 (interactive | |
1256 (let ((enable-recursive-minibuffers t) | |
438 | 1257 (minibuffer-history-sexp-flag nil) |
1258 (minibuffer-max-depth (and minibuffer-max-depth | |
1259 (1+ minibuffer-max-depth)))) | |
428 | 1260 (if (eq 't (symbol-value minibuffer-history-variable)) |
1261 (error "History is not being recorded in this context")) | |
1262 (list (read-from-minibuffer "Previous element matching (regexp): " | |
1263 (car minibuffer-history-search-history) | |
1264 minibuffer-local-map | |
1265 nil | |
1266 'minibuffer-history-search-history) | |
1267 (prefix-numeric-value current-prefix-arg)))) | |
1268 (let ((history (symbol-value minibuffer-history-variable)) | |
1269 prevpos | |
1270 (pos minibuffer-history-position)) | |
1271 (if (eq history t) | |
1272 (error "History is not being recorded in this context")) | |
1273 (while (/= n 0) | |
1274 (setq prevpos pos) | |
1275 (setq pos (min (max 1 (+ pos (if (< n 0) -1 1))) (length history))) | |
1276 (if (= pos prevpos) | |
1277 (if (= pos 1) ;; rewritten for I18N3 snarfing | |
1278 (error "No later matching history item") | |
1279 (error "No earlier matching history item"))) | |
1280 (if (string-match regexp | |
1281 (if minibuffer-history-sexp-flag | |
1282 (let ((print-level nil)) | |
1283 (prin1-to-string (nth (1- pos) history))) | |
1284 (nth (1- pos) history))) | |
1285 (setq n (+ n (if (< n 0) 1 -1))))) | |
1286 (setq minibuffer-history-position pos) | |
1287 (setq current-minibuffer-contents (buffer-string) | |
1288 current-minibuffer-point (point)) | |
1289 (erase-buffer) | |
1290 (let ((elt (nth (1- pos) history))) | |
1291 (insert (if minibuffer-history-sexp-flag | |
1292 (let ((print-level nil)) | |
1293 (prin1-to-string elt)) | |
1294 elt))) | |
1295 (goto-char (point-min))) | |
1296 (if (or (eq (car (car command-history)) 'previous-matching-history-element) | |
1297 (eq (car (car command-history)) 'next-matching-history-element)) | |
1298 (setq command-history (cdr command-history)))) | |
1299 | |
1300 (defun next-matching-history-element (regexp n) | |
1301 "Find the next history element that matches REGEXP. | |
1302 \(The next history element refers to a more recent action.) | |
1303 With prefix argument N, search for Nth next match. | |
1304 If N is negative, find the previous or Nth previous match." | |
1305 (interactive | |
1306 (let ((enable-recursive-minibuffers t) | |
438 | 1307 (minibuffer-history-sexp-flag nil) |
1308 (minibuffer-max-depth (and minibuffer-max-depth | |
1309 (1+ minibuffer-max-depth)))) | |
428 | 1310 (if (eq t (symbol-value minibuffer-history-variable)) |
1311 (error "History is not being recorded in this context")) | |
1312 (list (read-from-minibuffer "Next element matching (regexp): " | |
1313 (car minibuffer-history-search-history) | |
1314 minibuffer-local-map | |
1315 nil | |
1316 'minibuffer-history-search-history) | |
1317 (prefix-numeric-value current-prefix-arg)))) | |
1318 (previous-matching-history-element regexp (- n))) | |
1319 | |
1320 (defun next-history-element (n) | |
1321 "Insert the next element of the minibuffer history into the minibuffer." | |
1322 (interactive "p") | |
1323 (if (eq 't (symbol-value minibuffer-history-variable)) | |
1324 (error "History is not being recorded in this context")) | |
1325 (unless (zerop n) | |
1326 (when (eq minibuffer-history-position | |
1327 initial-minibuffer-history-position) | |
1328 (setq current-minibuffer-contents (buffer-string) | |
1329 current-minibuffer-point (point))) | |
1330 (let ((narg (- minibuffer-history-position n)) | |
1331 (minimum (if minibuffer-default -1 0))) | |
442 | 1332 ;; a weird special case here; when in repeat-complex-command, we're |
1333 ;; trying to edit the top command, and minibuffer-history-position | |
1334 ;; points to 1, the next-to-top command. in this case, the top | |
1335 ;; command in the history is suppressed in favor of the one being | |
1336 ;; edited, and there is no more command below it, except maybe the | |
1337 ;; default. | |
1338 (if (and (zerop narg) (eq minibuffer-history-position | |
1339 initial-minibuffer-history-position)) | |
1340 (setq minimum (1+ minimum))) | |
428 | 1341 (cond ((< narg minimum) |
440 | 1342 (error (if minibuffer-default |
1343 "No following item in %s" | |
1344 "No following item in %s; no default available") | |
1345 minibuffer-history-variable)) | |
428 | 1346 ((> narg (length (symbol-value minibuffer-history-variable))) |
1347 (error "No preceding item in %s" minibuffer-history-variable))) | |
1348 (erase-buffer) | |
1349 (setq minibuffer-history-position narg) | |
1350 (if (eq narg initial-minibuffer-history-position) | |
1351 (progn | |
1352 (insert current-minibuffer-contents) | |
1353 (goto-char current-minibuffer-point)) | |
442 | 1354 (let ((elt (if (> narg 0) |
428 | 1355 (nth (1- minibuffer-history-position) |
1356 (symbol-value minibuffer-history-variable)) | |
1357 minibuffer-default))) | |
1358 (insert | |
1359 (if (not (stringp elt)) | |
1360 (let ((print-level nil)) | |
1361 (condition-case nil | |
1362 (let ((print-readably t) | |
1363 (print-escape-newlines t)) | |
1364 (prin1-to-string elt)) | |
1365 (error (prin1-to-string elt)))) | |
1366 elt))) | |
1367 ;; FSF has point-min here. | |
1368 (goto-char (point-max)))))) | |
1369 | |
1370 (defun previous-history-element (n) | |
1371 "Insert the previous element of the minibuffer history into the minibuffer." | |
1372 (interactive "p") | |
1373 (next-history-element (- n))) | |
1374 | |
1375 (defun next-complete-history-element (n) | |
1376 "Get next element of history which is a completion of minibuffer contents." | |
1377 (interactive "p") | |
1378 (let ((point-at-start (point))) | |
1379 (next-matching-history-element | |
1380 (concat "^" (regexp-quote (buffer-substring (point-min) (point)))) n) | |
1381 ;; next-matching-history-element always puts us at (point-min). | |
1382 ;; Move to the position we were at before changing the buffer contents. | |
1383 ;; This is still sensical, because the text before point has not changed. | |
1384 (goto-char point-at-start))) | |
1385 | |
1386 (defun previous-complete-history-element (n) | |
1387 "Get previous element of history which is a completion of minibuffer contents." | |
1388 (interactive "p") | |
1389 (next-complete-history-element (- n))) | |
1390 | |
1391 | |
1392 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
1393 ;;;; reading various things from a minibuffer ;;;; | |
1394 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
1395 | |
440 | 1396 (defun read-expression (prompt &optional initial-contents history default-value) |
1397 "Return a Lisp object read using the minibuffer, prompting with PROMPT. | |
1398 If non-nil, optional second arg INITIAL-CONTENTS is a string to insert | |
1399 in the minibuffer before reading. | |
1400 Third arg HISTORY, if non-nil, specifies a history list. | |
1401 Fourth arg DEFAULT-VALUE is the default value. If non-nil, it is used | |
1402 for history command, and as the value to return if the user enters the | |
1403 empty string." | |
428 | 1404 (let ((minibuffer-history-sexp-flag t) |
1405 ;; Semi-kludge to get around M-x C-x o M-ESC trying to do completion. | |
1406 (minibuffer-completion-table nil)) | |
1407 (read-from-minibuffer prompt | |
1408 initial-contents | |
1409 read-expression-map | |
1410 t | |
1411 (or history 'read-expression-history) | |
440 | 1412 lisp-mode-abbrev-table |
1413 default-value))) | |
428 | 1414 |
440 | 1415 (defun read-string (prompt &optional initial-contents history default-value) |
428 | 1416 "Return a string from the minibuffer, prompting with string PROMPT. |
1417 If non-nil, optional second arg INITIAL-CONTENTS is a string to insert | |
440 | 1418 in the minibuffer before reading. |
1419 Third arg HISTORY, if non-nil, specifies a history list. | |
1420 Fourth arg DEFAULT-VALUE is the default value. If non-nil, it is used | |
1421 for history command, and as the value to return if the user enters the | |
1422 empty string." | |
428 | 1423 (let ((minibuffer-completion-table nil)) |
1424 (read-from-minibuffer prompt | |
1425 initial-contents | |
1426 minibuffer-local-map | |
440 | 1427 nil history nil default-value))) |
428 | 1428 |
440 | 1429 (defun eval-minibuffer (prompt &optional initial-contents history default-value) |
428 | 1430 "Return value of Lisp expression read using the minibuffer. |
1431 Prompt with PROMPT. If non-nil, optional second arg INITIAL-CONTENTS | |
1432 is a string to insert in the minibuffer before reading. | |
440 | 1433 Third arg HISTORY, if non-nil, specifies a history list. |
1434 Fourth arg DEFAULT-VALUE is the default value. If non-nil, it is used | |
1435 for history command, and as the value to return if the user enters the | |
1436 empty string." | |
1437 (eval (read-expression prompt initial-contents history default-value))) | |
428 | 1438 |
1439 ;; The name `command-history' is already taken | |
1440 (defvar read-command-history '()) | |
1441 | |
440 | 1442 (defun read-command (prompt &optional default-value) |
428 | 1443 "Read the name of a command and return as a symbol. |
440 | 1444 Prompts with PROMPT. By default, return DEFAULT-VALUE." |
428 | 1445 (intern (completing-read prompt obarray 'commandp t nil |
1446 ;; 'command-history is not right here: that's a | |
1447 ;; list of evalable forms, not a history list. | |
1448 'read-command-history | |
440 | 1449 default-value))) |
428 | 1450 |
440 | 1451 (defun read-function (prompt &optional default-value) |
428 | 1452 "Read the name of a function and return as a symbol. |
440 | 1453 Prompts with PROMPT. By default, return DEFAULT-VALUE." |
428 | 1454 (intern (completing-read prompt obarray 'fboundp t nil |
440 | 1455 'function-history default-value))) |
428 | 1456 |
440 | 1457 (defun read-variable (prompt &optional default-value) |
428 | 1458 "Read the name of a user variable and return it as a symbol. |
440 | 1459 Prompts with PROMPT. By default, return DEFAULT-VALUE. |
428 | 1460 A user variable is one whose documentation starts with a `*' character." |
1461 (intern (completing-read prompt obarray 'user-variable-p t nil | |
442 | 1462 'variable-history |
1463 (if (symbolp default-value) | |
1464 (symbol-name default-value) | |
1465 default-value)))) | |
428 | 1466 |
4734
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1467 (defun read-buffer (prompt &optional default require-match exclude) |
428 | 1468 "Read the name of a buffer and return as a string. |
1469 Prompts with PROMPT. Optional second arg DEFAULT is value to return if user | |
1470 enters an empty line. If optional third arg REQUIRE-MATCH is non-nil, | |
4734
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1471 only existing buffer names are allowed. Optional fourth argument EXCLUDE is |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1472 a buffer or a list of buffers to exclude from the completion list." |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1473 (when (bufferp exclude) |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1474 (setq exclude (list exclude))) |
428 | 1475 (let ((prompt (if default |
1476 (format "%s(default %s) " | |
1477 (gettext prompt) (if (bufferp default) | |
1478 (buffer-name default) | |
1479 default)) | |
4734
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1480 prompt)) |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1481 (alist (mapcar #'(lambda (b) (cons (buffer-name b) b)) |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1482 (remove-if (lambda (elt) (member elt exclude)) |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1483 (buffer-list)))) |
74a5eaa67982
Make switch-to-buffer completion avoid current buffer.
Didier Verna <didier@xemacs.org>
parents:
4720
diff
changeset
|
1484 result) |
428 | 1485 (while (progn |
1486 (setq result (completing-read prompt alist nil require-match | |
430 | 1487 nil 'buffer-history |
434 | 1488 (if (bufferp default) |
1489 (buffer-name default) | |
1490 default))) | |
428 | 1491 (cond ((not (equal result "")) |
1492 nil) | |
1493 ((not require-match) | |
1494 (setq result default) | |
1495 nil) | |
1496 ((not default) | |
3000 | 1497 nil) |
428 | 1498 ((not (get-buffer default)) |
1499 t) | |
1500 (t | |
1501 (setq result default) | |
1502 nil)))) | |
1503 (if (bufferp result) | |
1504 (buffer-name result) | |
1505 result))) | |
1506 | |
440 | 1507 (defun read-number (prompt &optional integers-only default-value) |
1508 "Read a number from the minibuffer, prompting with PROMPT. | |
1509 If optional second argument INTEGERS-ONLY is non-nil, accept | |
1510 only integer input. | |
1511 If DEFAULT-VALUE is non-nil, return that if user enters an empty | |
1512 line." | |
428 | 1513 (let ((pred (if integers-only 'integerp 'numberp)) |
1514 num) | |
1515 (while (not (funcall pred num)) | |
1516 (setq num (condition-case () | |
1517 (let ((minibuffer-completion-table nil)) | |
1518 (read-from-minibuffer | |
1519 prompt (if num (prin1-to-string num)) nil t | |
440 | 1520 nil nil default-value)) |
428 | 1521 (input-error nil) |
1522 (invalid-read-syntax nil) | |
1523 (end-of-file nil))) | |
1524 (or (funcall pred num) (beep))) | |
1525 num)) | |
1526 | |
440 | 1527 (defun read-shell-command (prompt &optional initial-input history default-value) |
428 | 1528 "Just like read-string, but uses read-shell-command-map: |
1529 \\{read-shell-command-map}" | |
1530 (let ((minibuffer-completion-table nil)) | |
1531 (read-from-minibuffer prompt initial-input read-shell-command-map | |
440 | 1532 nil (or history 'shell-command-history) |
1533 nil default-value))) | |
428 | 1534 |
1535 | |
1536 ;;; This read-file-name stuff probably belongs in files.el | |
1537 | |
1538 ;; Quote "$" as "$$" to get it past substitute-in-file-name | |
1539 (defun un-substitute-in-file-name (string) | |
1540 (let ((regexp "\\$") | |
1541 (olen (length string)) | |
1542 new | |
1543 n o ch) | |
1544 (if (not (string-match regexp string)) | |
1545 string | |
1546 (setq n 1) | |
1547 (while (string-match regexp string (match-end 0)) | |
1548 (setq n (1+ n))) | |
1549 (setq new (make-string (+ olen n) ?$)) | |
1550 (setq n 0 o 0) | |
1551 (while (< o olen) | |
1552 (setq ch (aref string o)) | |
1553 (aset new n ch) | |
1554 (setq o (1+ o) n (1+ n)) | |
1555 (if (eq ch ?$) | |
1556 ;; already aset by make-string initial-value | |
1557 (setq n (1+ n)))) | |
1558 new))) | |
1559 | |
442 | 1560 |
1561 ;; Wrapper for `directory-files' for use in generating completion lists. | |
1562 ;; Generates output in the same format as `file-name-all-completions'. | |
1563 ;; | |
1564 ;; The EFS replacement for `directory-files' doesn't support the FILES-ONLY | |
1565 ;; option, so it has to be faked. The listing cache will hopefully | |
1566 ;; improve the performance of this operation. | |
1567 (defun minibuf-directory-files (dir &optional match-regexp files-only) | |
1568 (let ((want-file (or (eq files-only nil) (eq files-only t))) | |
1569 (want-dirs (or (eq files-only nil) (not (eq files-only t))))) | |
5267
668c73e222fd
Change forms like (delq nil (mapcar ...)) to (mapcan ...).
Aidan Kehoe <kehoea@parhasard.net>
parents:
4806
diff
changeset
|
1570 (mapcan |
668c73e222fd
Change forms like (delq nil (mapcar ...)) to (mapcan ...).
Aidan Kehoe <kehoea@parhasard.net>
parents:
4806
diff
changeset
|
1571 #'(lambda (f) |
668c73e222fd
Change forms like (delq nil (mapcar ...)) to (mapcan ...).
Aidan Kehoe <kehoea@parhasard.net>
parents:
4806
diff
changeset
|
1572 (and (not (equal "." f)) |
668c73e222fd
Change forms like (delq nil (mapcar ...)) to (mapcan ...).
Aidan Kehoe <kehoea@parhasard.net>
parents:
4806
diff
changeset
|
1573 (if (file-directory-p (expand-file-name f dir)) |
668c73e222fd
Change forms like (delq nil (mapcar ...)) to (mapcan ...).
Aidan Kehoe <kehoea@parhasard.net>
parents:
4806
diff
changeset
|
1574 (and want-dirs (list (file-name-as-directory f))) |
668c73e222fd
Change forms like (delq nil (mapcar ...)) to (mapcan ...).
Aidan Kehoe <kehoea@parhasard.net>
parents:
4806
diff
changeset
|
1575 (and want-file (list f))))) |
668c73e222fd
Change forms like (delq nil (mapcar ...)) to (mapcan ...).
Aidan Kehoe <kehoea@parhasard.net>
parents:
4806
diff
changeset
|
1576 (directory-files dir nil match-regexp)))) |
442 | 1577 |
1578 | |
428 | 1579 (defun read-file-name-2 (history prompt dir default |
1580 must-match initial-contents | |
1581 completer) | |
1582 (if (not dir) | |
1583 (setq dir default-directory)) | |
1584 (setq dir (abbreviate-file-name dir t)) | |
1585 (let* ((insert (cond ((and (not insert-default-directory) | |
1586 (not initial-contents)) | |
1587 "") | |
1588 (initial-contents | |
1589 (cons (un-substitute-in-file-name | |
1590 (concat dir initial-contents)) | |
1591 (length dir))) | |
1592 (t | |
1593 (un-substitute-in-file-name dir)))) | |
1594 (val | |
1595 ;; Hateful, broken, case-sensitive un*x | |
1596 ;;; (completing-read prompt | |
1597 ;;; completer | |
1598 ;;; dir | |
1599 ;;; must-match | |
1600 ;;; insert | |
1601 ;;; history) | |
1602 ;; #### - this is essentially the guts of completing read. | |
1603 ;; There should be an elegant way to pass a pair of keymaps to | |
1604 ;; completing read, but this will do for now. All sins are | |
1605 ;; relative. --Stig | |
1606 (let ((minibuffer-completion-table completer) | |
1607 (minibuffer-completion-predicate dir) | |
1608 (minibuffer-completion-confirm (if (eq must-match 't) | |
1609 nil t)) | |
1610 (last-exact-completion nil)) | |
1611 (read-from-minibuffer prompt | |
1612 insert | |
1613 (if (not must-match) | |
1614 read-file-name-map | |
1615 read-file-name-must-match-map) | |
1616 nil | |
434 | 1617 history |
1618 nil | |
1619 default)))) | |
428 | 1620 ;;; ;; Kludge! Put "/foo/bar" on history rather than "/default//foo/bar" |
1621 ;;; (let ((hist (cond ((not history) 'minibuffer-history) | |
1622 ;;; ((consp history) (car history)) | |
1623 ;;; (t history)))) | |
1624 ;;; (if (and val | |
1625 ;;; hist | |
1626 ;;; (not (eq hist 't)) | |
1627 ;;; (boundp hist) | |
1628 ;;; (equal (car-safe (symbol-value hist)) val)) | |
1629 ;;; (let ((e (condition-case nil | |
1630 ;;; (expand-file-name val) | |
1631 ;;; (error nil)))) | |
1632 ;;; (if (and e (not (equal e val))) | |
1633 ;;; (set hist (cons e (cdr (symbol-value hist)))))))) | |
1634 | |
1635 (cond ((not val) | |
1636 (error "No file name specified")) | |
1637 ((and default | |
1638 (equal val (if (consp insert) (car insert) insert))) | |
1639 default) | |
1640 (t | |
1641 (substitute-in-file-name val))))) | |
1642 | |
1643 ;; #### this function should use minibuffer-completion-table | |
1644 ;; or something. But that is sloooooow. | |
1645 ;; #### all this shit needs better documentation!!!!!!!! | |
1646 (defun read-file-name-activate-callback (event extent dir-p) | |
1647 ;; used as the activate-callback of the filename list items | |
1648 ;; in the completion buffer, in place of default-choose-completion. | |
1649 ;; if a regular file was selected, we call default-choose-completion | |
1650 ;; (which just inserts the string in the minibuffer and calls | |
1651 ;; exit-minibuffer). If a directory was selected, we display | |
1652 ;; the contents of the directory. | |
1653 (let* ((file (extent-string extent)) | |
1654 (completion-buf (extent-object extent)) | |
1655 (minibuf (symbol-value-in-buffer 'completion-reference-buffer | |
1656 completion-buf)) | |
1657 (in-dir (file-name-directory (buffer-substring nil nil minibuf))) | |
1658 (full (expand-file-name file in-dir))) | |
1659 (if (not (file-directory-p full)) | |
1660 (default-choose-completion event extent minibuf) | |
1661 (erase-buffer minibuf) | |
1662 (insert-string (file-name-as-directory | |
1663 (abbreviate-file-name full t)) minibuf) | |
1664 (reset-buffer completion-buf) | |
1665 (let ((standard-output completion-buf)) | |
1666 (display-completion-list | |
442 | 1667 (minibuf-directory-files full nil (if dir-p 'directory)) |
428 | 1668 :user-data dir-p |
1669 :reference-buffer minibuf | |
1670 :activate-callback 'read-file-name-activate-callback) | |
1671 (goto-char (point-min) completion-buf))))) | |
1672 | |
673 | 1673 (defun read-file-name-1 (type history prompt dir default |
1674 must-match initial-contents | |
1675 completer) | |
428 | 1676 (if (should-use-dialog-box-p) |
442 | 1677 (condition-case nil |
1678 (let ((file | |
1679 (apply #'make-dialog-box | |
673 | 1680 type `(:title ,(capitalize-string-as-title |
1681 ;; Kludge: Delete ": " off the end. | |
1682 (replace-in-string prompt ": $" "")) | |
1683 ,@(and dir (list :initial-directory | |
1684 dir)) | |
1685 :file-must-exist ,must-match | |
1686 ,@(and initial-contents | |
1687 (list :initial-filename | |
1688 initial-contents)))))) | |
442 | 1689 ;; hack -- until we implement reading a directory properly, |
1690 ;; allow a file as indicating the directory it's in | |
1691 (if (and (eq completer 'read-directory-name-internal) | |
1692 (not (file-directory-p file))) | |
1693 (file-name-directory file) | |
1694 file)) | |
1695 (unimplemented | |
1696 ;; this calls read-file-name-2 | |
1697 (mouse-read-file-name-1 history prompt dir default must-match | |
1698 initial-contents completer) | |
1699 )) | |
1700 (add-one-shot-hook | |
1701 'minibuffer-setup-hook | |
1702 (lambda () | |
4720
3c92890f3750
Add `file-system-ignore-case-p', use it.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4675
diff
changeset
|
1703 (and (file-system-ignore-case-p (or dir default-directory)) |
442 | 1704 (set (make-local-variable 'completion-ignore-case) t)) |
1705 (set | |
1706 (make-local-variable | |
1707 'completion-display-completion-list-function) | |
1708 #'(lambda (completions) | |
1709 (display-completion-list | |
1710 completions | |
1711 :user-data (not (eq completer 'read-file-name-internal)) | |
1712 :activate-callback | |
1713 'read-file-name-activate-callback))))) | |
1714 (read-file-name-2 history prompt dir default must-match | |
1715 initial-contents completer))) | |
428 | 1716 |
1717 (defun read-file-name (prompt | |
1718 &optional dir default must-match initial-contents | |
1719 history) | |
1720 "Read file name, prompting with PROMPT and completing in directory DIR. | |
1721 This will prompt with a dialog box if appropriate, according to | |
1722 `should-use-dialog-box-p'. | |
1723 Value is not expanded---you must call `expand-file-name' yourself. | |
438 | 1724 Value is subject to interpretation by `substitute-in-file-name' however. |
428 | 1725 Default name to DEFAULT if user enters a null string. |
1726 (If DEFAULT is omitted, the visited file name is used, | |
1727 except that if INITIAL-CONTENTS is specified, that combined with DIR is | |
1728 used.) | |
1729 Fourth arg MUST-MATCH non-nil means require existing file's name. | |
1730 Non-nil and non-t means also require confirmation after completion. | |
440 | 1731 Fifth arg INITIAL-CONTENTS specifies text to start with. If this is not |
1732 specified, and `insert-default-directory' is non-nil, DIR or the current | |
1733 directory will be used. | |
428 | 1734 Sixth arg HISTORY specifies the history list to use. Default is |
1735 `file-name-history'. | |
1736 DIR defaults to current buffer's directory default." | |
673 | 1737 (read-file-name-1 |
1738 'file (or history 'file-name-history) | |
428 | 1739 prompt dir (or default |
440 | 1740 (and initial-contents |
1741 (abbreviate-file-name (expand-file-name | |
1742 initial-contents dir) t)) | |
1743 (and buffer-file-truename | |
1744 (abbreviate-file-name buffer-file-name t))) | |
428 | 1745 must-match initial-contents |
1746 ;; A separate function (not an anonymous lambda-expression) | |
1747 ;; and passed as a symbol because of disgusting kludges in various | |
1748 ;; places which do stuff like (let ((filename-kludge-p (eq minibuffer-completion-table 'read-file-name-internal))) ...) | |
1749 'read-file-name-internal)) | |
1750 | |
1751 (defun read-directory-name (prompt | |
1752 &optional dir default must-match initial-contents | |
1753 history) | |
1754 "Read directory name, prompting with PROMPT and completing in directory DIR. | |
1755 This will prompt with a dialog box if appropriate, according to | |
1756 `should-use-dialog-box-p'. | |
1757 Value is not expanded---you must call `expand-file-name' yourself. | |
1758 Value is subject to interpreted by substitute-in-file-name however. | |
1759 Default name to DEFAULT if user enters a null string. | |
1760 (If DEFAULT is omitted, the current buffer's default directory is used.) | |
1761 Fourth arg MUST-MATCH non-nil means require existing directory's name. | |
1762 Non-nil and non-t means also require confirmation after completion. | |
1763 Fifth arg INITIAL-CONTENTS specifies text to start with. | |
1764 Sixth arg HISTORY specifies the history list to use. Default is | |
1765 `file-name-history'. | |
1766 DIR defaults to current buffer's directory default." | |
1767 (read-file-name-1 | |
673 | 1768 'directory (or history 'file-name-history) |
1769 prompt dir (or default default-directory) must-match initial-contents | |
1770 'read-directory-name-internal)) | |
428 | 1771 |
1772 | |
1773 ;; Environment-variable and ~username completion hack | |
1774 (defun read-file-name-internal-1 (string dir action completer) | |
1775 (if (not (string-match | |
1776 "\\([^$]\\|\\`\\)\\(\\$\\$\\)*\\$\\([A-Za-z0-9_]*\\|{[^}]*\\)\\'" | |
1777 string)) | |
1778 ;; Not doing environment-variable completion hack | |
1779 (let* ((orig (if (equal string "") nil string)) | |
4720
3c92890f3750
Add `file-system-ignore-case-p', use it.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4675
diff
changeset
|
1780 (completion-ignore-case (file-system-ignore-case-p |
3c92890f3750
Add `file-system-ignore-case-p', use it.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4675
diff
changeset
|
1781 (or dir default-directory))) |
428 | 1782 (sstring (if orig (substitute-in-file-name string) string)) |
1783 (specdir (if orig (file-name-directory sstring) nil)) | |
1784 (name (if orig (file-name-nondirectory sstring) string)) | |
1785 (direct (if specdir (expand-file-name specdir dir) dir))) | |
1786 ;; ~username completion | |
1787 (if (and (fboundp 'user-name-completion-1) | |
1788 (string-match "^[~]" name)) | |
1789 (let ((user (substring name 1))) | |
1790 (cond ((eq action 'lambda) | |
1791 (file-directory-p name)) | |
1792 ((eq action 't) | |
1793 ;; all completions | |
1794 (mapcar #'(lambda (p) (concat "~" p)) | |
502 | 1795 (declare-fboundp |
1796 (user-name-all-completions user)))) | |
428 | 1797 (t;; 'nil |
1798 ;; complete | |
502 | 1799 (let* ((val+uniq (declare-fboundp |
1800 (user-name-completion-1 user))) | |
428 | 1801 (val (car val+uniq)) |
1802 (uniq (cdr val+uniq))) | |
1803 (cond ((stringp val) | |
1804 (if uniq | |
1805 (file-name-as-directory (concat "~" val)) | |
1806 (concat "~" val))) | |
1807 ((eq val t) | |
1808 (file-name-as-directory name)) | |
1809 (t nil)))))) | |
1810 (funcall completer | |
1811 action | |
1812 orig | |
1813 sstring | |
1814 specdir | |
1815 direct | |
1816 name))) | |
1817 ;; An odd number of trailing $'s | |
1818 (let* ((start (match-beginning 3)) | |
4720
3c92890f3750
Add `file-system-ignore-case-p', use it.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4675
diff
changeset
|
1819 (completion-ignore-case (file-system-ignore-case-p |
3c92890f3750
Add `file-system-ignore-case-p', use it.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4675
diff
changeset
|
1820 (or dir default-directory))) |
428 | 1821 (env (substring string |
5366
f00192e1cd49
Examining the result of #'length: `eql', not `=', it's better style & cheaper
Aidan Kehoe <kehoea@parhasard.net>
parents:
5267
diff
changeset
|
1822 (cond ((eql start (length string)) |
428 | 1823 ;; "...$" |
1824 start) | |
5366
f00192e1cd49
Examining the result of #'length: `eql', not `=', it's better style & cheaper
Aidan Kehoe <kehoea@parhasard.net>
parents:
5267
diff
changeset
|
1825 ((eql (aref string start) ?{) |
428 | 1826 ;; "...${..." |
1827 (1+ start)) | |
1828 (t | |
1829 start)))) | |
1830 (head (substring string 0 (1- start))) | |
1831 (alist #'(lambda () | |
1832 (mapcar #'(lambda (x) | |
1833 (cons (substring x 0 (string-match "=" x)) | |
1834 nil)) | |
1835 process-environment)))) | |
1836 | |
1837 (cond ((eq action 'lambda) | |
1838 nil) | |
1839 ((eq action 't) | |
1840 ;; all completions | |
1841 (mapcar #'(lambda (p) | |
1842 (if (and (> (length p) 0) | |
1843 ;;#### Unix-specific | |
1844 ;;#### -- need absolute-pathname-p | |
1845 (/= (aref p 0) ?/)) | |
1846 (concat "$" p) | |
1847 (concat head "$" p))) | |
1848 (all-completions env (funcall alist)))) | |
1849 (t ;; nil | |
1850 ;; complete | |
1851 (let* ((e (funcall alist)) | |
1852 (val (try-completion env e))) | |
1853 (cond ((stringp val) | |
1854 (if (string-match "[^A-Za-z0-9_]" val) | |
1855 (concat head | |
1856 "${" val | |
1857 ;; completed uniquely? | |
1858 (if (eq (try-completion val e) 't) | |
1859 "}" "")) | |
1860 (concat head "$" val))) | |
1861 ((eql val 't) | |
1862 (concat head | |
1863 (un-substitute-in-file-name (getenv env)))) | |
1864 (t nil)))))))) | |
1865 | |
1866 | |
1867 (defun read-file-name-internal (string dir action) | |
1868 (read-file-name-internal-1 | |
1869 string dir action | |
1870 #'(lambda (action orig string specdir dir name) | |
1871 (cond ((eq action 'lambda) | |
1872 (if (not orig) | |
1873 nil | |
1874 (let ((sstring (condition-case nil | |
1875 (expand-file-name string) | |
1876 (error nil)))) | |
1877 (if (not sstring) | |
1878 ;; Some pathname syntax error in string | |
1879 nil | |
1880 (file-exists-p sstring))))) | |
1881 ((eq action 't) | |
1882 ;; all completions | |
1883 (mapcar #'un-substitute-in-file-name | |
442 | 1884 (if (string= name "") |
1885 (delete "./" (file-name-all-completions "" dir)) | |
1886 (file-name-all-completions name dir)))) | |
428 | 1887 (t;; nil |
1888 ;; complete | |
1889 (let* ((d (or dir default-directory)) | |
1890 (val (file-name-completion name d))) | |
1891 (if (and (eq val 't) | |
1892 (not (null completion-ignored-extensions))) | |
1893 ;;#### (file-name-completion "foo") returns 't | |
1894 ;; when both "foo" and "foo~" exist and the latter | |
1895 ;; is "pruned" by completion-ignored-extensions. | |
1896 ;; I think this is a bug in file-name-completion. | |
1897 (setq val (let ((completion-ignored-extensions '())) | |
1898 (file-name-completion name d)))) | |
1899 (if (stringp val) | |
1900 (un-substitute-in-file-name (if specdir | |
1901 (concat specdir val) | |
1902 val)) | |
1903 (let ((tem (un-substitute-in-file-name string))) | |
1904 (if (not (equal tem orig)) | |
1905 ;; substitute-in-file-name did something | |
1906 tem | |
1907 val))))))))) | |
1908 | |
1909 (defun read-directory-name-internal (string dir action) | |
1910 (read-file-name-internal-1 | |
1911 string dir action | |
1912 #'(lambda (action orig string specdir dir name) | |
1913 (let* ((dirs #'(lambda (fn) | |
1914 (let ((l (if (equal name "") | |
442 | 1915 (minibuf-directory-files |
428 | 1916 dir |
1917 "" | |
1918 'directories) | |
442 | 1919 (minibuf-directory-files |
428 | 1920 dir |
1921 (concat "\\`" (regexp-quote name)) | |
1922 'directories)))) | |
1923 (mapcar fn | |
1924 ;; Wretched unix | |
1925 (delete "." l)))))) | |
1926 (cond ((eq action 'lambda) | |
1927 ;; complete? | |
1928 (if (not orig) | |
1929 nil | |
1930 (file-directory-p string))) | |
1931 ((eq action 't) | |
1932 ;; all completions | |
1933 (funcall dirs #'(lambda (n) | |
1934 (un-substitute-in-file-name | |
1935 (file-name-as-directory n))))) | |
1936 (t | |
1937 ;; complete | |
1938 (let ((val (try-completion | |
1939 name | |
1940 (funcall dirs | |
1941 #'(lambda (n) | |
1942 (list (file-name-as-directory | |
1943 n))))))) | |
1944 (if (stringp val) | |
1945 (un-substitute-in-file-name (if specdir | |
1946 (concat specdir val) | |
1947 val)) | |
1948 (let ((tem (un-substitute-in-file-name string))) | |
1949 (if (not (equal tem orig)) | |
1950 ;; substitute-in-file-name did something | |
1951 tem | |
1952 val)))))))))) | |
1953 | |
1954 (defun append-expand-filename (file-string string) | |
1955 "Append STRING to FILE-STRING differently depending on whether STRING | |
1956 is a username (~string), an environment variable ($string), | |
1957 or a filename (/string). The resultant string is returned with the | |
1958 environment variable or username expanded and resolved to indicate | |
1959 whether it is a file(/result) or a directory (/result/)." | |
1960 (let ((file | |
1961 (cond ((string-match "\\([~$]\\)\\([^~$/]*\\)$" file-string) | |
1962 (cond ((string= (substring file-string | |
1963 (match-beginning 1) | |
1964 (match-end 1)) "~") | |
1965 (concat (substring file-string 0 (match-end 1)) | |
1966 string)) | |
1967 (t (substitute-in-file-name | |
1968 (concat (substring file-string 0 (match-end 1)) | |
1969 string))))) | |
1970 (t (concat (file-name-directory | |
1971 (substitute-in-file-name file-string)) string)))) | |
1972 result) | |
1973 | |
1974 (cond ((stringp (setq result (and (file-exists-p (expand-file-name file)) | |
1975 (read-file-name-internal | |
1976 (condition-case nil | |
1977 (expand-file-name file) | |
1978 (error file)) | |
1979 "" nil)))) | |
1980 result) | |
1981 (t file)))) | |
1982 | |
442 | 1983 (defun mouse-rfn-setup-vars (prompt) |
1984 ;; a specifier would be nice. | |
1985 (set (make-local-variable 'frame-title-format) | |
1986 (capitalize-string-as-title | |
1987 ;; Kludge: Delete ": " off the end. | |
1988 (replace-in-string prompt ": $" ""))) | |
1989 ;; ensure that killing the frame works right, | |
1990 ;; instead of leaving us in the minibuffer. | |
1991 (add-local-hook 'delete-frame-hook | |
1992 #'(lambda (frame) | |
1993 (abort-recursive-edit)))) | |
1994 | |
428 | 1995 (defun mouse-file-display-completion-list (window dir minibuf user-data) |
1996 (let ((standard-output (window-buffer window))) | |
1997 (condition-case nil | |
1998 (display-completion-list | |
442 | 1999 (minibuf-directory-files dir nil t) |
2000 :window-width (window-width window) | |
2001 :window-height (window-text-area-height window) | |
2002 :completion-string "" | |
428 | 2003 :activate-callback |
2004 'mouse-read-file-name-activate-callback | |
2005 :user-data user-data | |
2006 :reference-buffer minibuf | |
2007 :help-string "") | |
442 | 2008 (t nil)) |
2009 )) | |
428 | 2010 |
2011 (defun mouse-directory-display-completion-list (window dir minibuf user-data) | |
2012 (let ((standard-output (window-buffer window))) | |
2013 (condition-case nil | |
2014 (display-completion-list | |
442 | 2015 (minibuf-directory-files dir nil 1) |
428 | 2016 :window-width (window-width window) |
442 | 2017 :window-height (window-text-area-height window) |
2018 :completion-string "" | |
428 | 2019 :activate-callback |
2020 'mouse-read-file-name-activate-callback | |
2021 :user-data user-data | |
2022 :reference-buffer minibuf | |
2023 :help-string "") | |
442 | 2024 (t nil)) |
2025 )) | |
428 | 2026 |
2027 (defun mouse-read-file-name-activate-callback (event extent user-data) | |
2028 (let* ((file (extent-string extent)) | |
2029 (minibuf (symbol-value-in-buffer 'completion-reference-buffer | |
2030 (extent-object extent))) | |
442 | 2031 (ministring (buffer-substring nil nil minibuf)) |
2032 (in-dir (file-name-directory ministring)) | |
428 | 2033 (full (expand-file-name file in-dir)) |
2034 (filebuf (nth 0 user-data)) | |
442 | 2035 (dirbuf (nth 1 user-data)) |
428 | 2036 (filewin (nth 2 user-data)) |
2037 (dirwin (nth 3 user-data))) | |
2038 (if (file-regular-p full) | |
2039 (default-choose-completion event extent minibuf) | |
2040 (erase-buffer minibuf) | |
2041 (insert-string (file-name-as-directory | |
2042 (abbreviate-file-name full t)) minibuf) | |
2043 (reset-buffer filebuf) | |
442 | 2044 (if (not dirbuf) |
428 | 2045 (mouse-directory-display-completion-list filewin full minibuf |
2046 user-data) | |
2047 (mouse-file-display-completion-list filewin full minibuf user-data) | |
442 | 2048 (reset-buffer dirbuf) |
428 | 2049 (mouse-directory-display-completion-list dirwin full minibuf |
2050 user-data))))) | |
2051 | |
442 | 2052 ;; our cheesy but god-awful time consuming file dialog box implementation. |
2053 ;; this will be replaced with use of the native file dialog box (when | |
2054 ;; available). | |
428 | 2055 (defun mouse-read-file-name-1 (history prompt dir default |
442 | 2056 must-match initial-contents |
2057 completer) | |
2058 ;; file-p is t if we're reading files, nil if directories. | |
428 | 2059 (let* ((file-p (eq 'read-file-name-internal completer)) |
2060 (filebuf (get-buffer-create "*Completions*")) | |
442 | 2061 (dirbuf (and file-p (generate-new-buffer " *mouse-read-file*"))) |
4376
53e507d77416
Fix problem with file dialog box.
Mike Sperber <sperber@deinprogramm.de>
parents:
4222
diff
changeset
|
2062 (butbuf (generate-new-buffer " *mouse-read-file-buttons*")) |
428 | 2063 (frame (make-dialog-frame)) |
2064 filewin dirwin | |
4384
c7e65155cb35
Improve upon previous patch to minibuf.el.
Mike Sperber <sperber@deinprogramm.de>
parents:
4376
diff
changeset
|
2065 user-data |
c7e65155cb35
Improve upon previous patch to minibuf.el.
Mike Sperber <sperber@deinprogramm.de>
parents:
4376
diff
changeset
|
2066 (window-min-height 1)) ; allow button window to be height 2 |
428 | 2067 (unwind-protect |
2068 (progn | |
2069 (reset-buffer filebuf) | |
442 | 2070 |
2071 ;; set up the frame. | |
2072 (focus-frame frame) | |
4384
c7e65155cb35
Improve upon previous patch to minibuf.el.
Mike Sperber <sperber@deinprogramm.de>
parents:
4376
diff
changeset
|
2073 (split-window nil (- (window-height) 2)) |
428 | 2074 (if file-p |
2075 (progn | |
2076 (split-window-horizontally 16) | |
2077 (setq filewin (frame-rightmost-window frame) | |
2078 dirwin (frame-leftmost-window frame)) | |
2079 (set-window-buffer filewin filebuf) | |
442 | 2080 (set-window-buffer dirwin dirbuf)) |
428 | 2081 (setq filewin (frame-highest-window frame)) |
2082 (set-window-buffer filewin filebuf)) | |
442 | 2083 (setq user-data (list filebuf dirbuf filewin dirwin)) |
2084 (set-window-buffer (frame-lowest-window frame) butbuf) | |
2085 | |
2086 ;; set up completion buffers. | |
2087 (let ((rfcshookfun | |
2088 ;; kludge! | |
2089 ;; #### I really need to flesh out the object | |
2090 ;; hierarchy better to avoid these kludges. | |
2091 ;; (?? I wrote this comment above some time ago, | |
2092 ;; and I don't understand what I'm referring to | |
2093 ;; any more. --ben | |
2094 (lambda () | |
2095 (mouse-rfn-setup-vars prompt) | |
5368
ed74d2ca7082
Use ', not #', when a given symbol may not have a function binding at read time
Aidan Kehoe <kehoea@parhasard.net>
parents:
5366
diff
changeset
|
2096 (when-boundp 'scrollbar-width |
442 | 2097 (set-specifier scrollbar-width 0 (current-buffer))) |
2098 (setq truncate-lines t)))) | |
2099 | |
2100 (set-buffer filebuf) | |
2101 (add-local-hook 'completion-setup-hook rfcshookfun) | |
2102 (when file-p | |
2103 (set-buffer dirbuf) | |
2104 (add-local-hook 'completion-setup-hook rfcshookfun))) | |
2105 | |
2106 ;; set up minibuffer. | |
2107 (add-one-shot-hook | |
2108 'minibuffer-setup-hook | |
2109 (lambda () | |
2110 (if (not file-p) | |
2111 (mouse-directory-display-completion-list | |
2112 filewin dir (current-buffer) user-data) | |
2113 (mouse-file-display-completion-list | |
2114 filewin dir (current-buffer) user-data) | |
2115 (mouse-directory-display-completion-list | |
2116 dirwin dir (current-buffer) user-data)) | |
2117 (set | |
2118 (make-local-variable | |
2119 'completion-display-completion-list-function) | |
2120 (lambda (completions) | |
2121 (display-completion-list | |
2122 completions | |
2123 :help-string "" | |
2124 :window-width (window-width filewin) | |
2125 :window-height (window-text-area-height filewin) | |
2126 :completion-string "" | |
2127 :activate-callback | |
2128 'mouse-read-file-name-activate-callback | |
2129 :user-data user-data))) | |
2130 (mouse-rfn-setup-vars prompt) | |
2131 (save-selected-window | |
2132 ;; kludge to ensure the frame title is correct. | |
2133 ;; the minibuffer leaves the frame title the way | |
2134 ;; it was before (i.e. of the selected window before | |
2135 ;; the dialog box was opened), so to get it correct | |
2136 ;; we have to be tricky. | |
2137 (select-window filewin) | |
2138 (redisplay-frame nil t) | |
2139 ;; #### another kludge. sometimes the focus ends up | |
2140 ;; back in the main window, not the dialog box. it | |
2141 ;; occurs randomly and it's not possible to reliably | |
2142 ;; reproduce. We try to fix it by draining non-user | |
2143 ;; events and then setting the focus back on the frame. | |
2144 (sit-for 0 t) | |
2145 (focus-frame frame)))) | |
2146 | |
2147 ;; set up button buffer. | |
2148 (set-buffer butbuf) | |
2149 (mouse-rfn-setup-vars prompt) | |
428 | 2150 (when dir |
2151 (setq default-directory dir)) | |
2152 (when (featurep 'scrollbar) | |
442 | 2153 (set-specifier scrollbar-width 0 butbuf)) |
428 | 2154 (insert " ") |
2155 (insert-gui-button (make-gui-button "OK" | |
2156 (lambda (foo) | |
2157 (exit-minibuffer)))) | |
2158 (insert " ") | |
2159 (insert-gui-button (make-gui-button "Cancel" | |
2160 (lambda (foo) | |
2161 (abort-recursive-edit)))) | |
442 | 2162 |
2163 ;; now start reading filename. | |
2164 (read-file-name-2 history prompt dir default | |
2165 must-match initial-contents | |
2166 completer)) | |
2167 | |
2168 ;; always clean up. | |
2169 ;; get rid of our hook that calls abort-recursive-edit -- not a good | |
2170 ;; idea here. | |
2171 (kill-local-variable 'delete-frame-hook) | |
428 | 2172 (delete-frame frame) |
2173 (kill-buffer filebuf) | |
442 | 2174 (kill-buffer butbuf) |
2175 (and dirbuf (kill-buffer dirbuf))))) | |
428 | 2176 |
2177 (defun read-face (prompt &optional must-match) | |
2178 "Read the name of a face from the minibuffer and return it as a symbol." | |
2179 (intern (completing-read prompt obarray 'find-face must-match))) | |
2180 | |
2181 (defun read-color-completion-table () | |
2527 | 2182 (mapcar #'list (color-list))) |
428 | 2183 |
2184 (defun read-color (prompt &optional must-match initial-contents) | |
2185 "Read the name of a color from the minibuffer. | |
2186 On X devices, this uses `x-library-search-path' to find rgb.txt in order | |
2187 to build a completion table. | |
2188 On TTY devices, this uses `tty-color-list'. | |
2189 On mswindows devices, this uses `mswindows-color-list'." | |
2190 (let ((table (read-color-completion-table))) | |
2191 (completing-read prompt table nil (and table must-match) | |
2192 initial-contents))) | |
2193 | |
2194 | |
2195 (defun read-coding-system (prompt &optional default-coding-system) | |
2196 "Read a coding-system (or nil) from the minibuffer. | |
2197 Prompting with string PROMPT. | |
2198 If the user enters null input, return second argument DEFAULT-CODING-SYSTEM. | |
2199 DEFAULT-CODING-SYSTEM can be a string, symbol, or coding-system object." | |
2200 (intern (completing-read prompt obarray 'find-coding-system t nil nil | |
2201 (cond ((symbolp default-coding-system) | |
2202 (symbol-name default-coding-system)) | |
2203 ((coding-system-p default-coding-system) | |
2204 (symbol-name (coding-system-name default-coding-system))) | |
2205 (t | |
2206 default-coding-system))))) | |
2207 | |
2208 (defun read-non-nil-coding-system (prompt) | |
2209 "Read a non-nil coding-system from the minibuffer. | |
2210 Prompt with string PROMPT." | |
2211 (let ((retval (intern ""))) | |
5366
f00192e1cd49
Examining the result of #'length: `eql', not `=', it's better style & cheaper
Aidan Kehoe <kehoea@parhasard.net>
parents:
5267
diff
changeset
|
2212 (while (eql 0 (length (symbol-name retval))) |
428 | 2213 (setq retval (intern (completing-read prompt obarray |
2214 'find-coding-system | |
2215 t)))) | |
2216 retval)) | |
2217 | |
2218 | |
2219 | |
2220 (defcustom force-dialog-box-use nil | |
2221 "*If non-nil, always use a dialog box for asking questions, if possible. | |
2222 You should *bind* this, not set it. This is useful if you're doing | |
2223 something mousy but which wasn't actually invoked using the mouse." | |
2224 :type 'boolean | |
2225 :group 'minibuffer) | |
2226 | |
2227 ;; We include this here rather than dialog.el so it is defined | |
2228 ;; even when dialog boxes are not present. | |
2229 (defun should-use-dialog-box-p () | |
2230 "If non-nil, questions should be asked with a dialog box instead of the | |
2231 minibuffer. This looks at `last-command-event' to see if it was a mouse | |
2232 event, and checks whether dialog-support exists and the current device | |
2233 supports dialog boxes. | |
2234 | |
2235 The dialog box is totally disabled if the variable `use-dialog-box' | |
2236 is set to nil." | |
2237 (and (featurep 'dialog) | |
2238 (device-on-window-system-p) | |
2239 use-dialog-box | |
2240 (or force-dialog-box-use | |
2241 (button-press-event-p last-command-event) | |
2242 (button-release-event-p last-command-event) | |
2243 (misc-user-event-p last-command-event)))) | |
2244 | |
2730 | 2245 (defun get-user-response (position question answers) |
2246 "Ask a question and get a response from the user, in minibuffer or dialog box. | |
2247 POSITION specifies which frame to use. | |
2248 This is normally an event or a window or frame. | |
2249 If POSITION is t or nil, it means to use the frame the mouse is on. | |
2250 The dialog box appears in the middle of the specified frame. | |
2251 | |
2252 QUESTION is the question to ask (it should end with a question mark followed | |
2253 by a space). | |
2254 | |
2255 ANSWERS are the possible answers. It is a list; each item looks like | |
2256 | |
2257 (KEY BUTTON-TEXT RESPONSE) | |
2258 | |
2259 where KEY is the key to be pressed in the minibuffer, BUTTON-TEXT is the | |
2260 text to be displayed in a dialog box button (you should put %_ in it to | |
2261 indicate the accelerator), and RESPONSE is a value (typically a symbol) | |
2262 to be returned if the user selects this response. KEY should be either a | |
2263 single character or a string; which one you use needs to be consistent for | |
2264 all responses and determines whether the user responds by hitting a single | |
2265 key or typing in a string and hitting ENTER. | |
2266 | |
2267 An item may also be just a string--that makes a nonselectable item in the | |
2268 dialog box and is ignored in the minibuffer. | |
2269 | |
2270 An item may also be nil -- that means to put all preceding items | |
2271 on the left of the dialog box and all following items on the right; ignored | |
2272 in the minibuffer." | |
2273 (if (should-use-dialog-box-p) | |
2274 (get-dialog-box-response | |
2275 position | |
2276 (cons question | |
2277 (mapcar #'(lambda (x) | |
2278 (cond | |
2279 ((null x) nil) | |
2280 ((stringp x) x) | |
2281 (t (cons (second x) (third x))))) | |
2282 answers))) | |
2283 (save-excursion | |
2284 (let* ((answers (remove-if-not #'consp answers)) | |
2285 (possible | |
2286 (gettext | |
5567
3bc58dc9d688
Replace #'flet by #'labels where appropriate, core code.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5474
diff
changeset
|
2287 (labels ((car-to-string-if (x) |
3bc58dc9d688
Replace #'flet by #'labels where appropriate, core code.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5474
diff
changeset
|
2288 (setq x (car x)) |
3bc58dc9d688
Replace #'flet by #'labels where appropriate, core code.
Aidan Kehoe <kehoea@parhasard.net>
parents:
5474
diff
changeset
|
2289 (if (stringp x) x (char-to-string x)))) |
2730 | 2290 (concat (mapconcat #'car-to-string-if |
2291 (butlast answers) ", ") " or " | |
2292 (car-to-string-if (car (last answers))))))) | |
2293 (question (gettext question)) | |
2294 (p (format "%s(%s) " question possible))) | |
2295 (block nil | |
2296 (if (stringp (caar answers)) | |
2297 ;; based on yes-or-no-p. | |
2298 (while t | |
2299 (let* ((ans (downcase (read-string p nil t))) ;no history | |
2300 (res (member* ans answers :test #'equal :key #'car))) | |
2301 (if res (return (third (car res))) | |
2302 (ding nil 'yes-or-no-p) | |
2303 (discard-input) | |
2304 (message "Please answer %s." possible) | |
2305 (sleep-for 2)))) | |
2306 ;; based on y-or-n-p. | |
2307 (save-excursion | |
2308 (let* ((pre "") event) | |
2309 (while t | |
2310 (if (let ((cursor-in-echo-area t) | |
2311 (inhibit-quit t)) | |
2312 (message "%s%s(%s) " pre question possible) | |
2313 (setq event (next-command-event event)) | |
2314 (condition-case nil | |
2315 (prog1 | |
2316 (or quit-flag (eq 'keyboard-quit | |
2317 (key-binding event))) | |
2318 (setq quit-flag nil)) | |
2319 (wrong-type-argument t))) | |
2320 (progn | |
2321 (message "%s%s(%s) %s" pre question possible | |
2322 (single-key-description event)) | |
2323 (setq quit-flag nil) | |
2324 (signal 'quit '()))) | |
2325 (let* ((keys (events-to-keys (vector event))) | |
2326 (def (lookup-key query-replace-map keys))) | |
2327 (cond | |
2328 ; ((eq def 'skip) | |
2329 ; (message "%s%sNo" question possible) | |
2330 ; (return nil)) | |
2331 ; ((eq def 'act) | |
2332 ; (message "%s%sYes" question possible) | |
2333 ; (return t)) | |
2334 ((eq def 'recenter) | |
2335 (recenter)) | |
2336 ((or (eq def 'quit) (eq def 'exit-prefix)) | |
2337 (signal 'quit '())) | |
2338 ((button-release-event-p event) ; ignore them | |
2339 nil) | |
2340 (t | |
2341 (let ((res (member* (event-to-character event) answers | |
2342 :key #'car))) | |
2343 (if res (return (third (car res))) | |
2344 (message "%s%s(%s) %s" pre question possible | |
2345 (single-key-description event)) | |
2346 (ding nil 'y-or-n-p) | |
2347 (discard-input) | |
5366
f00192e1cd49
Examining the result of #'length: `eql', not `=', it's better style & cheaper
Aidan Kehoe <kehoea@parhasard.net>
parents:
5267
diff
changeset
|
2348 (if (eql (length pre) 0) |
2730 | 2349 (setq pre (format "Please answer %s. " |
2350 ;; 17 parens! a record in | |
2351 ;; our lisp code. | |
2352 possible))))))))))))))))) | |
2353 | |
428 | 2354 ;;; minibuf.el ends here |