home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
new
/
util
/
edit
/
jade
/
lisp
/
prompt.jl
< prev
next >
Wrap
Lisp/Scheme
|
1994-10-03
|
13KB
|
404 lines
;;;; prompt.jl -- Prompt in a buffer with completion
;;; Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
;;; This file is part of Jade.
;;; Jade 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 2, or (at your option)
;;; any later version.
;;; Jade 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 Jade; see the file COPYING. If not, write to
;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
(defvar prompt-keymap (make-keylist))
(defvar prompt-buffer-list '()
"Stack of buffers which can be used for prompts.")
(bind-keys prompt-keymap
"TAB" 'prompt-complete-word
"RET" 'prompt-enter-line
"LMB-CLICK2" 'prompt-select-completion
"RMB-CLICK1" 'prompt-complete-word
"Meta-?" 'prompt-print-word-completions
"Ctrl-g" 'prompt-cancel)
;; Configuration variables
(defvar prompt-completion-function nil
"Optional function taking one argument, the string to be completed. It
should return a list of all matches.")
(defvar prompt-validate-function nil
"Optional function taking one argument, the string which has been entered.
Should return non-nil when this string may be accepted (and therefore the
prompt will end). If it returns the symbol t the string is returned as-is,
if some other non-nil value is returned *that* is the value returned by
the prompt.")
(defconst prompt-def-regexps ["." "^|$"]
"Default value of `prompt-word-regexps'")
(defvar prompt-word-regexps prompt-def-regexps
"Vector of two regexps; the values of `word-regexp' and `word-not-regexp'
for the prompt.")
(defvar prompt-list nil
"Used by the `prompt-complete-from-list' and `prompt-validate-from-list'
to supply possible completions.")
(defvar prompt-symbol-predicate nil
"Predicate used when prompting for symbols.")
(defvar amiga-use-file-req-p t
"*AMIGA ONLY*
When non-nil the normal ASL file requester is used when file names are
prompted for.")
(defvar prompt-buffer nil
"The buffer being used for the prompt.")
(defvar prompt-completions-pos nil
"Position at which the list of completions should be printed.")
;; Main entrypoint
(defun prompt2 (&optional title start)
"Prompts for a string using completion. TITLE is the optional title to
print in the buffer, START the original contents of the buffer.
The string entered is returned, or nil if the prompt is cancelled (by Ctrl-g)."
(let*
(prompt-buffer
prompt-line-pos
prompt-completions-pos
result)
(if prompt-buffer-list
(setq prompt-buffer (car prompt-buffer-list)
prompt-buffer-list (cdr prompt-buffer-list))
(setq prompt-buffer (make-buffer "*prompt*")))
(setq buffer-list (cons prompt-buffer buffer-list))
(set-buffer-special prompt-buffer t)
(with-buffer prompt-buffer
(setq word-regexp (aref prompt-word-regexps 0)
word-not-regexp (aref prompt-word-regexps 1))
(if (stringp title)
(insert title)
(insert "Enter string:"))
(if (stringp start)
(format (current-buffer) "\n\n%s\n\n" start)
(insert "\n\n\n\n"))
(insert "::Completions::\n")
(setq prompt-completions-pos (cursor-pos))
(goto-char (line-end (prev-line 3)))
(setq keymap-path '(prompt-keymap global-keymap)
buffer-undo-list nil
result (catch 'prompt (recursive-edit))
buffer-list (delq prompt-buffer buffer-list)))
(clear-buffer prompt-buffer)
(setq prompt-buffer-list (cons prompt-buffer prompt-buffer-list))
result))
;; Subroutines
(defun prompt-enter-line (&optional whole-line)
(interactive)
(let*
((pos (if (and (> (cursor-pos) prompt-completions-pos)
whole-line)
(line-end)
(cursor-pos)))
(line (copy-area (line-start) pos)))
(if (or (not prompt-validate-function)
(let
((res (funcall prompt-validate-function line)))
(when (and res (not (eq res t)))
(setq line res))
res))
(throw 'prompt line)
(beep))))
(defun prompt-select-completion ()
(interactive)
(goto-char (mouse-pos))
(prompt-enter-line t))
;; Returns the number of completions found.
(defun prompt-complete-word ()
(interactive)
(if (not prompt-completion-function)
(progn
(message "No completion in this prompt!")
0)
(let*
((word-pos (or (word-start (left-char))
(line-start)))
(word (copy-area word-pos (cursor-pos)))
(comp-list (funcall prompt-completion-function word))
(num-found (length comp-list))
(buffer-record-undo nil))
(cond
((= num-found 0)
(delete-area prompt-completions-pos (buffer-end))
(message "No completions."))
((= num-found 1)
(goto-char (replace-string word (car comp-list) word-pos))
(delete-area prompt-completions-pos (buffer-end))
(message "Unique completion."))
(t
(prompt-print-completions comp-list)
(when (not (string-head-eq (car comp-list) word))
;; Completions don't match their source at all.
(delete-area word-pos (cursor-pos))
(setq word ""))
(goto-char (replace-string word
(make-completion-string word comp-list)
word-pos))
(format t "%d completions." num-found)))
num-found)))
(defun prompt-print-completions (comp-list)
(let*
((ipos (copy-pos prompt-completions-pos))
;; Don't want to record undo information for the completion list
(buffer-record-undo nil))
(delete-area ipos (buffer-end))
(insert "\n" ipos)
(while (consp comp-list)
(format (cons (current-buffer) ipos) "%s\n" (car comp-list))
(setq comp-list (cdr comp-list)))))
(defun prompt-print-word-completions ()
(interactive)
(prompt-print-completions
(funcall prompt-comp-func
(copy-area (or (word-start (left-char))
(line-start))
(cursor-pos)))))
(defun prompt-cancel ()
(interactive)
(message "Quit!")
(throw 'prompt nil))
;; Various completion/validation functions
(defun prompt-complete-symbol (word)
(mapcar 'symbol-name (apropos (concat ?^ word) prompt-symbol-predicate)))
(defun prompt-validate-symbol (name)
(and (find-symbol name)
(or (not prompt-symbol-predicate)
(funcall prompt-symbol-predicate (find-symbol name)))))
(defun prompt-complete-buffer (word)
(delete-if-not #'(lambda (b)
(string-head-eq b word))
(mapcar 'buffer-name buffer-list)))
(defun prompt-validate-buffer (name)
(if (equal name "")
t
(get-buffer name)))
(defvar prompt-file-exclude '"\\.(o|jlc|x)$|~$|^#.*#$"
"A regexp, if it matches the file being considered for completion, the file
is rejected.")
;; Don't want .info files (WB icons) on Amigas, everywhere else they're okay
;; though.
(when (amiga-p)
(setq prompt-file-exclude (concat prompt-file-exclude "|\\.info$")))
;; Ignore the `.' and `..' directory entries in UNIX
(when (unix-p)
(setq prompt-file-exclude (concat prompt-file-exclude "|^\\.(\\.|)$")))
(defun prompt-complete-filename (word)
(setq word (expand-file-name word))
(let*
((path (file-name-directory word))
(file (file-name-nondirectory word))
(files (directory-files path)))
(mapcar #'(lambda (x &aux y)
(when (file-directory-p (setq y (concat path x)))
(setq y (concat y ?/)))
y)
(delete-if #'(lambda (f)
(or (not (string-head-eq f file))
(regexp-match prompt-file-exclude f)))
files))))
(defun prompt-validate-filename (name)
(file-exists-p name))
(defun prompt-complete-directory (word)
(setq word (expand-file-name word))
(let
((path (file-name-directory word))
(file (file-name-nondirectory word)))
(delq 'nil
(mapcar #'(lambda (x)
(when (file-directory-p (concat path x))
(concat path x ?/)))
(delete-if #'(lambda (f)
(not (string-head-eq f file)))
(directory-files path))))))
(defun prompt-validate-directory (name)
(file-directory-p name))