Mercurial > hg > xemacs-beta
diff lisp/vm/vm-minibuf.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 859a2309aef8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/vm/vm-minibuf.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,400 @@ +;;; Minibuffer read functions for VM +;;; Copyright (C) 1993, 1994 Kyle E. Jones +;;; +;;; This program is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 1, or (at your option) +;;; any later version. +;;; +;;; This program is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program; if not, write to the Free Software +;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +(provide 'vm-minibuf) + +(defun vm-minibuffer-complete-word (&optional exiting) + (interactive) + (let ((opoint (point)) + trimmed-c-list c-list beg end diff word word-prefix-regexp completion) + ;; find the beginning and end of the word we're trying to complete + (if (or (eobp) (memq (following-char) '(?\t ?\n ?\ ))) + (progn + (skip-chars-backward " \t\n") + (and (not (eobp)) (forward-char)) + (setq end (point))) + (skip-chars-forward "^ \t\n") + (setq end (point))) + (skip-chars-backward "^ \t\n") + (setq beg (point)) + (goto-char opoint) + ;; copy the word into a string + (setq word (buffer-substring beg end)) + ;; trim the completion list down to just likely candidates + ;; then convert it to an alist. + (setq word-prefix-regexp (concat "^" (regexp-quote word)) + trimmed-c-list (vm-delete-non-matching-strings + word-prefix-regexp + vm-minibuffer-completion-table) + trimmed-c-list (mapcar 'list trimmed-c-list) + c-list (mapcar 'list vm-minibuffer-completion-table)) + ;; Try the word against the completion list. + (and trimmed-c-list + (setq completion (try-completion word trimmed-c-list))) + ;; If completion is nil, figure out what prefix of the word would prefix + ;; something in the completion list... but only if the user is interested. + (if (and (null completion) vm-completion-auto-correct c-list) + (let ((i -1)) + (while (null (setq completion + (try-completion (substring word 0 i) c-list))) + (vm-decrement i)) + (setq completion (substring word 0 i)))) + ;; If completion is t, we had a perfect match already. + (if (eq completion t) + (cond ((and (cdr trimmed-c-list) + (not (eq last-command 'vm-minibuffer-complete-word))) + (and (not exiting) + (vm-minibuffer-completion-message + "[Complete, but not unique]"))) + (vm-completion-auto-space + (goto-char end) + (insert " ")) + (t + (and (not exiting) + (vm-minibuffer-completion-message "[Sole completion]")))) + ;; Compute the difference in length between the completion and the + ;; word. A negative difference means no match and the magnitude + ;; indicates the number of chars that need to be shaved off the end + ;; before a match will occur. A positive difference means a match + ;; occurred and the magnitude specifies the number of new chars that + ;; can be appended to the word as a completion. + ;; + ;; `completion' can be nil here, but the code works anyway because + ;; (length nil) still equals 0! + (setq diff (- (length completion) (length word))) + (cond + ;; We have some completion chars. Insert them. + ((> diff 0) + (goto-char end) + (insert (substring completion (- diff))) + (if (and vm-completion-auto-space + (null (cdr trimmed-c-list))) + (insert " "))) + ;; The word prefixed more than one string, but we can't complete + ;; any further. Either give help or say "Ambiguous". + ((zerop diff) + (and (not exiting) + (if (null completion-auto-help) + (vm-minibuffer-completion-message "[Ambiguous]") + (vm-minibuffer-show-completions (sort + (mapcar 'car trimmed-c-list) + 'string-lessp))))) + ;; The word didn't prefix anything... if vm-completion-auto-correct is + ;; non-nil strip the offending characters and try again. + (vm-completion-auto-correct + (goto-char end) + (delete-char diff) + (vm-minibuffer-complete-word exiting)) + ;; if we're not auto-correcting and we're doing + ;; multi-word, just let the user insert a space. + (vm-completion-auto-space + (insert " ")) + ;; completion utterly failed, tell the user so. + (t + (and (not exiting) + (vm-minibuffer-completion-message "[No match]"))))))) + +(defun vm-minibuffer-complete-word-and-exit () + (interactive) + (vm-minibuffer-complete-word t) + (exit-minibuffer)) + +(defun vm-minibuffer-completion-message (string &optional seconds) + "Briefly display STRING to the right of the current minibuffer input. +Optional second arg SECONDS specifies how long to keep the message visible; +the default is 2 seconds. + +A keypress causes the immediate erasure of the STRING, and return of control +to the calling program." + (let (omax (inhibit-quit t)) + (save-excursion + (goto-char (point-max)) + (setq omax (point)) + (insert " " string)) + (sit-for (or seconds 2)) + (delete-region omax (point-max)))) + +(defun vm-minibuffer-replace-word (word) + (goto-char (point-max)) + (skip-chars-backward "^ \t\n") + (delete-region (point) (point-max)) + (insert word)) + +(defun vm-minibuffer-show-completions (list) + "Display LIST in a multi-column listing in the \" *Completions*\" buffer. +LIST should be a list of strings." + (save-excursion + (set-buffer (get-buffer-create " *Completions*")) + (setq buffer-read-only nil) + (use-local-map (make-sparse-keymap)) + ;; ignore vm-mutable-* here. the user shouldn't mind + ;; because when they exit the minibuffer the windows will be + ;; set right again. + (display-buffer (current-buffer)) + (erase-buffer) + (insert "Possible completions are:\n") + (setq buffer-read-only t) + (vm-show-list list 'vm-minibuffer-replace-word + (list (current-local-map) minibuffer-local-map)) + (goto-char (point-min)))) + +(defun vm-show-list (list &optional function keymaps) + "Display LIST in a multi-column listing in the current buffer at point. +The current buffer must be displayed in some window at the time +this function is called. + +LIST should be a list of strings. + +Optional second argument FUNCTION will be called if the mouse is +clicked on one of the strings in the current buffer. The string +clicked upon will be passed to FUNCTION as its sole argument. + +Optional third argument KEYMAPS specifies a lists of keymaps +where the FUNCTION should be bound to the mouse clicks. By +default the local keymap of the current buffer is used." + (or keymaps (setq keymaps (and (current-local-map) + (list (current-local-map))))) + (save-excursion + (let ((buffer-read-only nil) + tab-stops longest rows columns list-length q i w start command + keymap) + (cond ((and function keymaps (vm-mouse-support-possible-p)) + (setq command + (list 'lambda '(e) '(interactive "e") + (list 'let + '((string (vm-mouse-get-mouse-track-string e))) + (list 'and 'string (list function 'string))))) + (while keymaps + (setq keymap (car keymaps)) + (cond ((vm-mouse-xemacs-mouse-p) + (define-key keymap 'button1 command) + (define-key keymap 'button2 command) + (define-key keymap 'button3 command)) + ((vm-mouse-fsfemacs-mouse-p) + (define-key keymap [down-mouse-1] 'ignore) + (define-key keymap [drag-mouse-1] 'ignore) + (define-key keymap [mouse-1] command) + (define-key keymap [drag-mouse-2] 'ignore) + (define-key keymap [down-mouse-2] 'ignore) + (define-key keymap [mouse-2] command) + (define-key keymap [drag-mouse-3] 'ignore) + (define-key keymap [down-mouse-3] 'ignore) + (define-key keymap [mouse-3] command))) + (setq keymaps (cdr keymaps))))) + (setq w (vm-get-buffer-window (current-buffer))) + (setq q list + list-length 0 + longest 0) + (while q + (setq longest (max longest (length (car q))) + list-length (1+ list-length) + q (cdr q))) + ;; provide for separation between columns + (setq longest (+ 3 longest)) + (setq columns (max 1 (/ (- (window-width w) 2) longest)) + rows (/ list-length columns) + rows + (+ (if (zerop (% list-length columns)) 0 1) + rows)) + (setq i columns + tab-stops nil) + (while (not (zerop i)) + (setq tab-stops (cons (* longest i) tab-stops) + i (1- i))) + (setq q list + i 0) + (while q + (setq start (point)) + (insert (car q)) + (and function (vm-mouse-set-mouse-track-highlight start (point))) + (setq i (1+ i) + q (cdr q)) + (if (zerop (% i columns)) + (insert "\n") + (let ((tab-stop-list tab-stops)) + (tab-to-tab-stop))))))) + +(defun vm-minibuffer-completion-help () + (interactive) + (let ((opoint (point)) + c-list beg end word word-prefix-regexp) + ;; find the beginning and end of the word we're trying to complete + (if (or (eobp) (memq (following-char) '(?\t ?\n ?\ ))) + (progn + (skip-chars-backward " \t\n") + (and (not (eobp)) (forward-char)) + (setq end (point))) + (skip-chars-forward "^ \t\n") + (setq end (point))) + (skip-chars-backward "^ \t\n") + (setq beg (point)) + (goto-char opoint) + ;; copy the word into a string + (setq word (buffer-substring beg end)) + ;; trim the completion list down to just likely candidates + ;; then convert it to an alist. + (setq word-prefix-regexp (concat "^" (regexp-quote word)) + c-list (vm-delete-non-matching-strings + word-prefix-regexp + vm-minibuffer-completion-table) + c-list (sort c-list (function string-lessp))) + (if c-list + (vm-minibuffer-show-completions c-list) + (vm-minibuffer-completion-message " [No match]")))) + +(defun vm-keyboard-read-string (prompt completion-list &optional multi-word) + (let ((minibuffer-local-map (copy-keymap minibuffer-local-map)) + (vm-completion-auto-space multi-word) + (vm-minibuffer-completion-table completion-list)) + (define-key minibuffer-local-map "\t" 'vm-minibuffer-complete-word) + (define-key minibuffer-local-map " " 'vm-minibuffer-complete-word) + (define-key minibuffer-local-map "?" 'vm-minibuffer-completion-help) + (if (not multi-word) + (define-key minibuffer-local-map "\r" + 'vm-minibuffer-complete-word-and-exit)) + (read-string prompt))) + +(defvar last-nonmenu-event) + +(defun vm-read-string (prompt completion-list &optional multi-word) + ;; handle alist + (if (consp (car completion-list)) + (setq completion-list (nreverse (mapcar 'car completion-list)))) + (if (and completion-list (vm-mouse-support-possible-p)) + (cond ((and (vm-mouse-xemacs-mouse-p) + (or (button-press-event-p last-command-event) + (button-release-event-p last-command-event) + (menu-event-p last-command-event))) + (vm-mouse-read-string prompt completion-list multi-word)) + ((and (vm-mouse-fsfemacs-mouse-p) + (listp last-nonmenu-event)) + (vm-mouse-read-string prompt completion-list multi-word)) + (t + (vm-keyboard-read-string prompt completion-list multi-word))) + (vm-keyboard-read-string prompt completion-list multi-word))) + +(defun vm-read-number (prompt) + (let (result) + (while + (null + (string-match "^[ \t]*-?[0-9]+" (setq result (read-string prompt))))) + (string-to-int result))) + +(defun vm-read-password (prompt &optional confirm) + "Read and return a password from the minibuffer, prompting with PROMPT. +Optional second argument CONFIRM non-nil means that the user will be asked + to type the password a second time for confirmation and if there is a + mismatch, the process is repeated. + +Line editing keys are: + C-h, DEL rubout + C-u, C-x line kill + C-q, C-v literal next" + (catch 'return-value + (save-excursion + (let ((cursor-in-echo-area t) + (echo-keystrokes 0) + (input-buffer nil) + (help-form nil) + (xxx "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") + (string nil) + char done form) + (unwind-protect + (save-excursion + (setq input-buffer (get-buffer-create " *password*")) + (set-buffer input-buffer) + (while t + (erase-buffer) + (vm-unsaved-message "%s%s" prompt + (vm-truncate-string xxx (buffer-size))) + (while (not (memq (setq char (read-char)) '(?\C-m ?\C-j))) + (if (setq form + (cdr + (assq char + '((?\C-h . (delete-char -1)) + (?\C-? . (delete-char -1)) + (?\C-u . (delete-region 1 (point))) + (?\C-x . (delete-region 1 (point))) + (?\C-q . (quoted-insert 1)) + (?\C-v . (quoted-insert 1)))))) + (condition-case error-data + (eval form) + (error t)) + (insert char)) + (vm-unsaved-message "%s%s" prompt + (vm-truncate-string xxx (buffer-size)))) + (cond ((and confirm string) + (cond ((not (string= string (buffer-string))) + (vm-unsaved-message + (concat prompt + (vm-truncate-string xxx (buffer-size)) + " [Mismatch... try again.]")) + (ding) + (sit-for 2) + (setq string nil)) + (t (throw 'return-value string)))) + (confirm + (setq string (buffer-string)) + (vm-unsaved-message + (concat prompt + (vm-truncate-string xxx (buffer-size)) + " [Retype to confirm...]")) + (sit-for 2)) + (t + (vm-unsaved-message "") + (throw 'return-value (buffer-string)))))) + (and input-buffer (kill-buffer input-buffer))))))) + +(defun vm-keyboard-read-file-name (prompt &optional dir default + must-match initial history) + "Like read-file-name, except HISTORY's value is unaltered." + (let ((oldvalue (symbol-value history))) + (unwind-protect + (condition-case nil + (read-file-name prompt dir default must-match initial history) + (wrong-number-of-arguments + (if history + (let ((file-name-history (symbol-value history)) + file) + (setq file + (read-file-name prompt dir default must-match initial)) + file ) + (read-file-name prompt dir default must-match initial)))) + (and history (set history oldvalue))))) + +(defun vm-read-file-name (prompt &optional dir default + must-match initial history) + "Like read-file-name, except a mouse interface is used if a mouse +click mouse triggered the current command." + (if (vm-mouse-support-possible-p) + (cond ((and (vm-mouse-xemacs-mouse-p) + (or (button-press-event-p last-command-event) + (button-release-event-p last-command-event) + (menu-event-p last-command-event))) + (vm-mouse-read-file-name prompt dir default + must-match initial history)) + ((and (vm-mouse-fsfemacs-mouse-p) + (listp last-nonmenu-event)) + (vm-mouse-read-file-name prompt dir default + must-match initial history)) + (t + (vm-keyboard-read-file-name prompt dir default + must-match initial history))) + (vm-keyboard-read-file-name prompt dir default + must-match initial history))) + +