~ubuntu-branches/ubuntu/hardy/vm/hardy

« back to all changes in this revision

Viewing changes to vm-minibuf.el

  • Committer: Bazaar Package Importer
  • Author(s): Manoj Srivastava
  • Date: 2002-03-06 00:46:29 UTC
  • Revision ID: james.westby@ubuntu.com-20020306004629-lnksqjffsnoc4tog
Tags: upstream-7.03
ImportĀ upstreamĀ versionĀ 7.03

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;; Minibuffer read functions for VM
 
2
;;; Copyright (C) 1993, 1994 Kyle E. Jones
 
3
;;;
 
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)
 
7
;;; any later version.
 
8
;;;
 
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.
 
13
;;;
 
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.
 
17
 
 
18
(provide 'vm-minibuf)
 
19
 
 
20
(defun vm-minibuffer-complete-word (&optional exiting)
 
21
  (interactive)
 
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)
 
31
                     (point-min)))
 
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 ?\ )))
 
36
        (progn
 
37
          (skip-chars-backward " \t\n")   
 
38
          (and (not (eobp)) (forward-char))
 
39
          (setq end (point)))
 
40
      (skip-chars-forward "^ \t\n")
 
41
      (setq end (point)))
 
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)
 
45
        (setq beg point-min)
 
46
      (skip-chars-backward "^ \t\n")
 
47
      (setq beg (point)))
 
48
    (goto-char opoint)
 
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
 
55
                          word-prefix-regexp
 
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.
 
61
    (and trimmed-c-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)
 
66
        (let ((i -1))
 
67
          (while (null (setq completion
 
68
                             (try-completion (substring word 0 i) c-list)))
 
69
            (vm-decrement i))
 
70
          (setq completion (substring word 0 i))))
 
71
    ;; If completion is t, we had a perfect match already.
 
72
    (if (eq completion t)
 
73
        (cond (vm-completion-auto-space
 
74
               (goto-char end)
 
75
               (insert " "))
 
76
              (t
 
77
               (and (not exiting)
 
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.
 
85
      ;;
 
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)))
 
89
      (cond
 
90
       ;; We have some completion chars.  Insert them.
 
91
       ((or (> diff 0)
 
92
            (and (zerop diff) (not (string-equal completion word))))
 
93
        (goto-char end)
 
94
        (delete-char (- (length word)))
 
95
        (insert completion)
 
96
        (if (and vm-completion-auto-space
 
97
                 (null (cdr trimmed-c-list)))
 
98
            (insert " ")))
 
99
       ;; The word prefixed more than one string, but we can't complete
 
100
       ;; any further.  Either give help or say "Ambiguous".
 
101
       ((zerop diff)
 
102
        (and (not exiting)
 
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
 
107
                                                       (mapcar 'car
 
108
                                                               trimmed-c-list)
 
109
                                                       'string-lessp))))
 
110
                   ((not (eq last-command 'vm-minibuffer-complete-word))
 
111
                    (vm-minibuffer-completion-message
 
112
                     "[Complete, but not unique]"))
 
113
                   (vm-completion-auto-space
 
114
                    (insert " ")))))
 
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
 
118
        (goto-char end)
 
119
        (delete-char diff)
 
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
 
124
        (insert " "))
 
125
       ;; completion utterly failed, tell the user so.
 
126
       (t
 
127
        (and (not exiting)
 
128
             (vm-minibuffer-completion-message "[No match]")))))))
 
129
 
 
130
(defun vm-minibuffer-complete-word-and-exit ()
 
131
  (interactive)
 
132
  (vm-minibuffer-complete-word t)
 
133
  (exit-minibuffer))
 
134
 
 
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.
 
139
 
 
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))
 
143
    (save-excursion
 
144
      (goto-char (point-max))
 
145
      (setq omax (point))
 
146
      (insert " " string))
 
147
    (sit-for (or seconds 2))
 
148
    (delete-region omax (point-max))))
 
149
 
 
150
(defun vm-minibuffer-replace-word (word)
 
151
  (goto-char (point-max))
 
152
  (skip-chars-backward "^ \t\n")
 
153
  (delete-region (point) (point-max))
 
154
  (insert word))
 
155
 
 
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."
 
159
  (save-excursion
 
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
 
165
    ;; set right again.
 
166
    (display-buffer (current-buffer))
 
167
    (erase-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))))
 
173
 
 
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.
 
178
 
 
179
LIST should be a list of strings.
 
180
 
 
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.
 
184
 
 
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)))))
 
190
  (save-excursion
 
191
    (let ((buffer-read-only nil)
 
192
          (separation 3)
 
193
          tabs longest columns list-length q i w start command
 
194
          keymap)
 
195
      (cond ((and function keymaps (vm-mouse-support-possible-p))
 
196
             (setq command
 
197
                   (list 'lambda '(e) '(interactive "e")
 
198
                         (list 'let
 
199
                               '((string (vm-mouse-get-mouse-track-string e)))
 
200
                               (list 'and 'string (list function 'string)))))
 
201
             (while keymaps
 
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))
 
216
            q list
 
217
            list-length 0
 
218
            longest 0
 
219
            columns (1- (window-width w)))
 
220
      (while q
 
221
        (setq longest (max longest (length (car q)))
 
222
              list-length (1+ list-length)
 
223
              q (cdr q)))
 
224
      (setq tabs (/ list-length (/ columns (+ longest separation)))
 
225
            tabs (+ tabs
 
226
                    (if (zerop (% list-length
 
227
                                  (/ columns (+ longest separation))))
 
228
                        0
 
229
                      1)))
 
230
      (setq i 0)
 
231
      (while (< i tabs)
 
232
        (setq q (nthcdr i list))
 
233
        (while q
 
234
          (setq start (point))
 
235
          (insert (car q))
 
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)))
 
239
        (setq i (1+ i))
 
240
        (insert "\n")))))
 
241
 
 
242
(defun vm-minibuffer-completion-help ()
 
243
  (interactive)
 
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 ?\ )))
 
248
        (progn
 
249
          (skip-chars-backward " \t\n")   
 
250
          (and (not (eobp)) (forward-char))
 
251
          (setq end (point)))
 
252
      (skip-chars-forward "^ \t\n")
 
253
      (setq end (point)))
 
254
    (skip-chars-backward "^ \t\n")
 
255
    (setq beg (point))
 
256
    (goto-char opoint)
 
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
 
263
                  word-prefix-regexp
 
264
                  vm-minibuffer-completion-table)
 
265
          c-list (sort c-list (function string-lessp)))
 
266
    (if c-list
 
267
        (vm-minibuffer-show-completions c-list)
 
268
      (vm-minibuffer-completion-message " [No match]"))))
 
269
 
 
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)
 
277
    (if (not multi-word)
 
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))))
 
283
 
 
284
(defvar last-nonmenu-event)
 
285
 
 
286
(defun vm-read-string (prompt completion-list &optional multi-word)
 
287
  ;; handle alist
 
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))
 
299
            (t
 
300
             (vm-keyboard-read-string prompt completion-list multi-word)))
 
301
    (vm-keyboard-read-string prompt completion-list multi-word)))
 
302
 
 
303
(defun vm-read-number (prompt)
 
304
  (let (result)
 
305
    (while
 
306
        (null
 
307
         (string-match "^[ \t]*-?[0-9]+" (setq result (read-string prompt)))))
 
308
    (string-to-int result)))
 
309
 
 
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.
 
315
 
 
316
Line editing keys are:
 
317
  C-h, DEL      rubout
 
318
  C-u, C-x      line kill
 
319
  C-q, C-v      literal next"
 
320
  (catch 'return-value
 
321
    (save-excursion
 
322
      (let ((cursor-in-echo-area t)
 
323
            (echo-keystrokes 0)
 
324
            (input-buffer nil)
 
325
            (help-form nil)
 
326
            (xxx "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
 
327
            (string nil)
 
328
            char done form)
 
329
        (unwind-protect
 
330
            (save-excursion
 
331
              (setq input-buffer (get-buffer-create " *password*"))
 
332
              (set-buffer input-buffer)
 
333
              (while t
 
334
                (erase-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)))
 
338
                  (if (setq form
 
339
                            (cdr
 
340
                             (assq char
 
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
 
348
                          (eval form)
 
349
                        (error t))
 
350
                    (insert char))
 
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)))
 
355
                              (message
 
356
                               (concat prompt
 
357
                                       (vm-truncate-roman-string
 
358
                                        xxx (buffer-size))
 
359
                                       " [Mismatch... try again.]"))
 
360
                              (ding)
 
361
                              (sit-for 2)
 
362
                              (setq string nil))
 
363
                             (t (throw 'return-value string))))
 
364
                      (confirm
 
365
                       (setq string (buffer-string))
 
366
                       (message
 
367
                        (concat prompt
 
368
                                (vm-truncate-roman-string xxx (buffer-size))
 
369
                                " [Retype to confirm...]"))
 
370
                       (sit-for 2))
 
371
                      (t
 
372
                       (message "")
 
373
                       (throw 'return-value (buffer-string))))))
 
374
          (and input-buffer (kill-buffer input-buffer)))))))
 
375
 
 
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))
 
382
    (unwind-protect
 
383
        (condition-case nil
 
384
            (read-file-name prompt dir default must-match initial history)
 
385
          (wrong-number-of-arguments
 
386
           (if history
 
387
               (let ((file-name-history (symbol-value history))
 
388
                     file)
 
389
                 (setq file
 
390
                       (read-file-name prompt dir default must-match initial))
 
391
                 file )
 
392
             (read-file-name prompt dir default must-match initial))))
 
393
      (and history (set history oldvalue)))))
 
394
 
 
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))
 
410
            (t
 
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)))
 
415
 
 
416