1
;;; Minibuffer read functions for VM
2
;;; Copyright (C) 1993, 1994 Kyle E. Jones
4
;;; This program is free software; you can redistribute it and/or modify
5
;;; it under the terms of the GNU General Public License as published by
6
;;; the Free Software Foundation; either version 1, or (at your option)
9
;;; This program is distributed in the hope that it will be useful,
10
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
;;; GNU General Public License for more details.
14
;;; You should have received a copy of the GNU General Public License
15
;;; along with this program; if not, write to the Free Software
16
;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
(defun vm-minibuffer-complete-word (&optional exiting)
22
(let ((opoint (point))
23
;; In Emacs 21, during a minibuffer read the minibuffer
24
;; contains the prompt as buffer text and that text is
25
;; read only. So we can no longer assume that (point-min)
26
;; is where the user-entered text starts and we must avoid
27
;; modifying that prompt text. The value we want instead
28
;; of (point-min) is (minibuffer-prompt-end).
29
(point-min (if (fboundp 'minibuffer-prompt-end)
30
(minibuffer-prompt-end)
32
(case-fold-search completion-ignore-case)
33
trimmed-c-list c-list beg end diff word word-prefix-regexp completion)
34
;; find the beginning and end of the word we're trying to complete
35
(if (or (eobp) (memq (following-char) '(?\t ?\n ?\ )))
37
(skip-chars-backward " \t\n")
38
(and (not (eobp)) (forward-char))
40
(skip-chars-forward "^ \t\n")
42
;; if there can't be multiple words in the input the beginning
43
;; of the word must be at point-min.
44
(if (not vm-completion-auto-space)
46
(skip-chars-backward "^ \t\n")
49
;; copy the word into a string
50
(setq word (buffer-substring beg end))
51
;; trim the completion list down to just likely candidates
52
;; then convert it to an alist.
53
(setq word-prefix-regexp (concat "^" (regexp-quote word))
54
trimmed-c-list (vm-delete-non-matching-strings
56
vm-minibuffer-completion-table)
57
trimmed-c-list (sort trimmed-c-list (function string-lessp))
58
trimmed-c-list (mapcar 'list trimmed-c-list)
59
c-list (mapcar 'list vm-minibuffer-completion-table))
60
;; Try the word against the completion list.
62
(setq completion (try-completion word trimmed-c-list)))
63
;; If completion is nil, figure out what prefix of the word would prefix
64
;; something in the completion list... but only if the user is interested.
65
(if (and (null completion) vm-completion-auto-correct c-list)
67
(while (null (setq completion
68
(try-completion (substring word 0 i) c-list)))
70
(setq completion (substring word 0 i))))
71
;; If completion is t, we had a perfect match already.
73
(cond (vm-completion-auto-space
78
(vm-minibuffer-completion-message "[Sole completion]"))))
79
;; Compute the difference in length between the completion and the
80
;; word. A negative difference means no match and the magnitude
81
;; indicates the number of chars that need to be shaved off the end
82
;; before a match will occur. A positive difference means a match
83
;; occurred and the magnitude specifies the number of new chars that
84
;; can be appended to the word as a completion.
86
;; `completion' can be nil here, but the code works anyway because
87
;; (length nil) still equals 0!
88
(setq diff (- (length completion) (length word)))
90
;; We have some completion chars. Insert them.
92
(and (zerop diff) (not (string-equal completion word))))
94
(delete-char (- (length word)))
96
(if (and vm-completion-auto-space
97
(null (cdr trimmed-c-list)))
99
;; The word prefixed more than one string, but we can't complete
100
;; any further. Either give help or say "Ambiguous".
103
(cond ((> (length (car (car trimmed-c-list))) (length word))
104
(if (null completion-auto-help)
105
(vm-minibuffer-completion-message "[Ambiguous]")
106
(vm-minibuffer-show-completions (sort
110
((not (eq last-command 'vm-minibuffer-complete-word))
111
(vm-minibuffer-completion-message
112
"[Complete, but not unique]"))
113
(vm-completion-auto-space
115
;; The word didn't prefix anything... if vm-completion-auto-correct is
116
;; non-nil strip the offending characters and try again.
117
(vm-completion-auto-correct
120
(vm-minibuffer-complete-word exiting))
121
;; if we're not auto-correcting and we're doing
122
;; multi-word, just let the user insert a space.
123
(vm-completion-auto-space
125
;; completion utterly failed, tell the user so.
128
(vm-minibuffer-completion-message "[No match]")))))))
130
(defun vm-minibuffer-complete-word-and-exit ()
132
(vm-minibuffer-complete-word t)
135
(defun vm-minibuffer-completion-message (string &optional seconds)
136
"Briefly display STRING to the right of the current minibuffer input.
137
Optional second arg SECONDS specifies how long to keep the message visible;
138
the default is 2 seconds.
140
A keypress causes the immediate erasure of the STRING, and return of control
141
to the calling program."
142
(let (omax (inhibit-quit t))
144
(goto-char (point-max))
147
(sit-for (or seconds 2))
148
(delete-region omax (point-max))))
150
(defun vm-minibuffer-replace-word (word)
151
(goto-char (point-max))
152
(skip-chars-backward "^ \t\n")
153
(delete-region (point) (point-max))
156
(defun vm-minibuffer-show-completions (list)
157
"Display LIST in a multi-column listing in the \" *Completions*\" buffer.
158
LIST should be a list of strings."
160
(set-buffer (get-buffer-create " *Completions*"))
161
(setq buffer-read-only nil)
162
(use-local-map (make-sparse-keymap))
163
;; ignore vm-mutable-* here. the user shouldn't mind
164
;; because when they exit the minibuffer the windows will be
166
(display-buffer (current-buffer))
168
(insert "Possible completions are:\n")
169
(setq buffer-read-only t)
170
(vm-show-list list 'vm-minibuffer-replace-word
171
(list (current-local-map) minibuffer-local-map))
172
(goto-char (point-min))))
174
(defun vm-show-list (list &optional function keymaps)
175
"Display LIST in a multi-column listing in the current buffer at point.
176
The current buffer must be displayed in some window at the time
177
this function is called.
179
LIST should be a list of strings.
181
Optional second argument FUNCTION will be called if the mouse is
182
clicked on one of the strings in the current buffer. The string
183
clicked upon will be passed to FUNCTION as its sole argument.
185
Optional third argument KEYMAPS specifies a lists of keymaps
186
where the FUNCTION should be bound to the mouse clicks. By
187
default the local keymap of the current buffer is used."
188
(or keymaps (setq keymaps (and (current-local-map)
189
(list (current-local-map)))))
191
(let ((buffer-read-only nil)
193
tabs longest columns list-length q i w start command
195
(cond ((and function keymaps (vm-mouse-support-possible-p))
197
(list 'lambda '(e) '(interactive "e")
199
'((string (vm-mouse-get-mouse-track-string e)))
200
(list 'and 'string (list function 'string)))))
202
(setq keymap (car keymaps))
203
(cond ((vm-mouse-xemacs-mouse-p)
204
(define-key keymap 'button1 command)
205
(define-key keymap 'button2 command))
206
((vm-mouse-fsfemacs-mouse-p)
207
(define-key keymap [down-mouse-1] 'ignore)
208
(define-key keymap [drag-mouse-1] 'ignore)
209
(define-key keymap [mouse-1] command)
210
(define-key keymap [drag-mouse-2] 'ignore)
211
(define-key keymap [down-mouse-2] 'ignore)
212
(define-key keymap [mouse-2] command)))
213
(setq keymaps (cdr keymaps)))))
214
(setq list (sort (copy-sequence list) (function string-lessp))
215
w (vm-get-buffer-window (current-buffer))
219
columns (1- (window-width w)))
221
(setq longest (max longest (length (car q)))
222
list-length (1+ list-length)
224
(setq tabs (/ list-length (/ columns (+ longest separation)))
226
(if (zerop (% list-length
227
(/ columns (+ longest separation))))
232
(setq q (nthcdr i list))
236
(and function (vm-mouse-set-mouse-track-highlight start (point)))
237
(insert-char ? (+ separation (- longest (length (car q)))))
238
(setq q (nthcdr tabs q)))
242
(defun vm-minibuffer-completion-help ()
244
(let ((opoint (point))
245
c-list beg end word word-prefix-regexp)
246
;; find the beginning and end of the word we're trying to complete
247
(if (or (eobp) (memq (following-char) '(?\t ?\n ?\ )))
249
(skip-chars-backward " \t\n")
250
(and (not (eobp)) (forward-char))
252
(skip-chars-forward "^ \t\n")
254
(skip-chars-backward "^ \t\n")
257
;; copy the word into a string
258
(setq word (buffer-substring beg end))
259
;; trim the completion list down to just likely candidates
260
;; then convert it to an alist.
261
(setq word-prefix-regexp (concat "^" (regexp-quote word))
262
c-list (vm-delete-non-matching-strings
264
vm-minibuffer-completion-table)
265
c-list (sort c-list (function string-lessp)))
267
(vm-minibuffer-show-completions c-list)
268
(vm-minibuffer-completion-message " [No match]"))))
270
(defun vm-keyboard-read-string (prompt completion-list &optional multi-word)
271
(let ((minibuffer-local-map (copy-keymap minibuffer-local-map))
272
(vm-completion-auto-space multi-word)
273
(vm-minibuffer-completion-table completion-list))
274
(define-key minibuffer-local-map "\t" 'vm-minibuffer-complete-word)
275
(define-key minibuffer-local-map " " 'vm-minibuffer-complete-word)
276
(define-key minibuffer-local-map "?" 'vm-minibuffer-completion-help)
278
(define-key minibuffer-local-map "\r"
279
'vm-minibuffer-complete-word-and-exit))
280
;; evade the XEmacs dialog box, yeccch.
281
(let ((use-dialog-box nil))
282
(read-string prompt))))
284
(defvar last-nonmenu-event)
286
(defun vm-read-string (prompt completion-list &optional multi-word)
288
(if (consp (car completion-list))
289
(setq completion-list (nreverse (mapcar 'car completion-list))))
290
(if (and completion-list (vm-mouse-support-possible-here-p))
291
(cond ((and (vm-mouse-xemacs-mouse-p)
292
(or (button-press-event-p last-command-event)
293
(button-release-event-p last-command-event)
294
(menu-event-p last-command-event)))
295
(vm-mouse-read-string prompt completion-list multi-word))
296
((and (vm-mouse-fsfemacs-mouse-p)
297
(listp last-nonmenu-event))
298
(vm-mouse-read-string prompt completion-list multi-word))
300
(vm-keyboard-read-string prompt completion-list multi-word)))
301
(vm-keyboard-read-string prompt completion-list multi-word)))
303
(defun vm-read-number (prompt)
307
(string-match "^[ \t]*-?[0-9]+" (setq result (read-string prompt)))))
308
(string-to-int result)))
310
(defun vm-read-password (prompt &optional confirm)
311
"Read and return a password from the minibuffer, prompting with PROMPT.
312
Optional second argument CONFIRM non-nil means that the user will be asked
313
to type the password a second time for confirmation and if there is a
314
mismatch, the process is repeated.
316
Line editing keys are:
319
C-q, C-v literal next"
322
(let ((cursor-in-echo-area t)
326
(xxx "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
331
(setq input-buffer (get-buffer-create " *password*"))
332
(set-buffer input-buffer)
335
(message "%s%s" prompt
336
(vm-truncate-roman-string xxx (buffer-size)))
337
(while (not (memq (setq char (read-char)) '(?\C-m ?\C-j)))
341
'((?\C-h . (delete-char -1))
342
(?\C-? . (delete-char -1))
343
(?\C-u . (delete-region 1 (point)))
344
(?\C-x . (delete-region 1 (point)))
345
(?\C-q . (quoted-insert 1))
346
(?\C-v . (quoted-insert 1))))))
347
(condition-case error-data
351
(message "%s%s" prompt
352
(vm-truncate-roman-string xxx (buffer-size))))
353
(cond ((and confirm string)
354
(cond ((not (string= string (buffer-string)))
357
(vm-truncate-roman-string
359
" [Mismatch... try again.]"))
363
(t (throw 'return-value string))))
365
(setq string (buffer-string))
368
(vm-truncate-roman-string xxx (buffer-size))
369
" [Retype to confirm...]"))
373
(throw 'return-value (buffer-string))))))
374
(and input-buffer (kill-buffer input-buffer)))))))
376
(defun vm-keyboard-read-file-name (prompt &optional dir default
377
must-match initial history)
378
"Like read-file-name, except HISTORY's value is unaltered."
379
(let ((oldvalue (symbol-value history))
380
;; evade the XEmacs dialog box, yeccch.
381
(use-dialog-box nil))
384
(read-file-name prompt dir default must-match initial history)
385
(wrong-number-of-arguments
387
(let ((file-name-history (symbol-value history))
390
(read-file-name prompt dir default must-match initial))
392
(read-file-name prompt dir default must-match initial))))
393
(and history (set history oldvalue)))))
395
(defun vm-read-file-name (prompt &optional dir default
396
must-match initial history)
397
"Like read-file-name, except a mouse interface is used if a mouse
398
click mouse triggered the current command."
399
(if (vm-mouse-support-possible-here-p)
400
(cond ((and (vm-mouse-xemacs-mouse-p)
401
(or (button-press-event-p last-command-event)
402
(button-release-event-p last-command-event)
403
(menu-event-p last-command-event)))
404
(vm-mouse-read-file-name prompt dir default
405
must-match initial history))
406
((and (vm-mouse-fsfemacs-mouse-p)
407
(listp last-nonmenu-event))
408
(vm-mouse-read-file-name prompt dir default
409
must-match initial history))
411
(vm-keyboard-read-file-name prompt dir default
412
must-match initial history)))
413
(vm-keyboard-read-file-name prompt dir default
414
must-match initial history)))