diff lisp/ilisp/completer.new.el @ 4:b82b59fe008d r19-15b3

Import from CVS: tag r19-15b3
author cvs
date Mon, 13 Aug 2007 08:46:56 +0200
parents
children ec9a17fef872
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/ilisp/completer.new.el	Mon Aug 13 08:46:56 2007 +0200
@@ -0,0 +1,1013 @@
+;;; -*-Emacs-Lisp-*-
+;;;%Header
+;;;
+;;; Rcs_Info: completer.el,v 3.23 1993/09/03 02:05:07 ivan Rel $
+;;;
+;;; Partial completion mechanism for GNU Emacs.  Version 3.03
+;;; Copyright (C) 1990, 1991, 1992 Chris McConnell, ccm@cs.cmu.edu.
+;;; Thanks to Bjorn Victor for suggestions, testing, and patches for
+;;; file completion. 
+
+;;; This file is part of GNU Emacs.
+
+;;; GNU Emacs is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY.  No author or distributor
+;;; accepts responsibility to anyone for the consequences of using it
+;;; or for whether it serves any particular purpose or works at all,
+;;; unless he says so in writing.  Refer to the GNU Emacs General Public
+;;; License for full details.
+;;; Everyone is granted permission to copy, modify and redistribute
+;;; GNU Emacs, but only under the conditions described in the
+;;; GNU Emacs General Public License.   A copy of this license is
+;;; supposed to have been given to you along with GNU Emacs so you
+;;; can know your rights and responsibilities.  It should be in a
+;;; file named COPYING.  Among other things, the copyright notice
+;;; and this notice must be preserved on all copies.
+
+;;; When loaded, this file extends the standard completion mechanisms
+;;; so that they perform pattern matching completions.  There is also
+;;; an interface that allows it to be used by other programs.  The
+;;; completion rules are:
+;;;
+;;; 1) If what has been typed matches any possibility, do normal
+;;; completion. 
+;;;
+;;; 2) Otherwise, generate a regular expression such that
+;;; completer-words delimit words and generate all possible matches.
+;;; The variable completer-any-delimiter can be set to a character
+;;; that matches any delimiter.  If it were " ", then "by  d" would be 
+;;; byte-recompile-directory.  If completer-use-words is T, a match is
+;;; unique if it is the only one with the same number of words.  If
+;;; completer-use-words is NIL, a match is unique if it is the only
+;;; possibility.  If you ask the completer to use its best guess, it
+;;; will be the shortest match of the possibilities unless
+;;; completer-exact is T.
+;;;
+;;; 3) For filenames, if completer-complete-filenames is T, each
+;;; pathname component will be individually completed, otherwise only
+;;; the final component will be completed.  If you are using a
+;;; distributed file system like afs, you may want to set up a
+;;; symbolic link in your home directory or add pathname components to
+;;; completer-file-skip so that the pathname components that go across
+;;; machines do not get expanded.
+;;;
+;;; SPACE, TAB, LFD, RET, and ? do normal completion if possible
+;;; otherwise they do partial completion.  In addition, C-DEL will
+;;; undo the last partial expansion or contraction.  M-RET will always
+;;; complete to the current match before returning.  This is useful
+;;; when any string is possible, but you want to complete to a string
+;;; as when calling find-file.  The bindings can be changed by using
+;;; completer-load-hook.
+;;;
+;;; Modes that use comint-dynamic-complete (like cmushell and ilisp)
+;;; will also do partial completion as will M-tab in Emacs LISP.
+;;;
+;;; Examples:
+;;; a-f     auto-fill-mode
+;;; b--d    *beginning-of-defun or byte-recompile-directory
+;;; by  d   *byte-recompile-directory if completer-any-delimiter is " "
+;;; ~/i.e   *~/ilisp.el or ~/il-el.el or ~/ilisp.elc
+;;; /u/mi/  /usr/misc/
+;;;
+
+;;;%Globals
+;;;%%Switches
+(defvar completer-load-hook nil
+  "Hook called when minibuffer partial completion is loaded.")
+
+(defvar completer-disable nil
+  "*If T, turn off partial completion.  Use the command
+\\[completer-toggle] to set this.")
+
+(defvar completer-complete-filenames t
+  "*If T, then each component of a filename will be completed,
+otherwise just the final component will be completed.")
+
+(defvar completer-use-words nil ; jwz: this is HATEFUL!
+  "*If T, then prefer completions with the same number of words as the
+pattern.")
+
+(defvar completer-words "---. <" 
+  "*Delimiters used in partial completions.  It should be a set of
+characters suitable for inclusion in a [] regular expression.")
+
+(defvar completer-any-delimiter nil
+  "*If a character, then a delimiter in the pattern that matches the
+character will match any delimiter in completer-words.")
+
+(defvar completer-file-skip "^cs/$\\|@sys\\|.edu/$\\|.gov/$\\|.com/$\\|:/$"
+  "*Regular expression for pathname components to not complete.")
+
+(defvar completer-exact nil
+  "*If T, then you must have an exact match.  Otherwise, the shortest
+string that matches the pattern will be used.")
+
+(defvar completer-cache-size 100
+  "*Size of cache to use for partially completed pathnames.")
+
+(defvar completer-use-cache t
+  "*Set to nil to disable the partially completed pathname cache.")
+
+;;;%%Internal
+(defvar completer-last-pattern ""
+  "The last pattern expanded.")
+
+(defvar completer-message nil
+  "T if temporary message was just displayed.")
+
+(defvar completer-path-cache nil
+  "Cache of (path . choices) for completer.")
+
+(defvar completer-string nil "Last completer string.")
+(defvar completer-table nil "Last completer table.")
+(defvar completer-pred nil "Last completer pred.")
+(defvar completer-mode nil "Last completer mode.")
+(defvar completer-result nil "Last completer result.")
+
+;;;%Utilities
+(defun completer-message (message &optional point)
+  "Display MESSAGE at optional POINT for two seconds."
+  (setq point (or point (point-max))
+	completer-message t)
+  (let ((end
+	 (save-excursion
+	   (goto-char point)
+	   (insert message)
+	   (point)))
+	(inhibit-quit t))
+    (sit-for 2)
+    (delete-region point end)
+    (if (and quit-flag 
+	     ;;(not (eq 'lucid-19 ilisp-emacs-version-id))
+	     (not (string-match "Lucid" emacs-version))
+	     )
+	(setq quit-flag nil
+	      unread-command-char 7))))
+
+;;;
+(defun completer-deleter (regexp choices &optional keep)
+  "Destructively remove strings that match REGEXP in CHOICES and
+return the modified list.  If optional KEEP, then keep entries that
+match regexp."
+  (let* ((choiceb choices)
+	 choicep)
+    (if keep
+	(progn
+	  (while (and choiceb (not (string-match regexp (car choiceb))))
+	    (setq choiceb (cdr choiceb)))
+	  (setq choicep choiceb)
+	  (while (cdr choicep)
+	    (if (string-match regexp (car (cdr choicep)))
+		(setq choicep (cdr choicep))
+		(rplacd choicep (cdr (cdr choicep))))))
+	(while (and choiceb (string-match regexp (car choiceb)))
+	  (setq choiceb (cdr choiceb)))
+	(setq choicep choiceb)
+	(while (cdr choicep)
+	  (if (string-match regexp (car (cdr choicep)))
+	      (rplacd choicep (cdr (cdr choicep)))
+	      (setq choicep (cdr choicep)))))
+    choiceb))
+
+;;;%%Regexp
+(defun completer-regexp (string delimiters any)
+  "Convert STRING into a regexp with words delimited by characters in
+DELIMITERS.  Any delimiter in STRING that is the same as ANY will
+match any delimiter."
+  (let* ((delimiter-reg (concat "[" delimiters "]"))
+	 (limit (length string))
+	 (pos 0)
+	 (regexp "^"))
+    (while (and (< pos limit) (string-match delimiter-reg string pos))
+      (let* ((begin (match-beginning 0))
+	     (end (match-end 0))
+	     (delimiter (substring string begin end))
+	     (anyp (eq (elt string begin) any)))
+	(setq regexp 
+	      (format "%s%s[^%s]*%s" 
+		      regexp
+		      (regexp-quote (substring string pos begin))
+		      (if anyp delimiters delimiter)
+		      (if anyp delimiter-reg delimiter))
+	      pos end)))
+    (if (<= pos limit)
+	(setq regexp (concat regexp 
+			     (regexp-quote (substring string pos limit)))))))
+
+;;;
+(defun completer-words (regexp string &optional limit)
+  "Return the number of words matching REGEXP in STRING up to LIMIT."
+  (setq limit (or limit 1000))
+  (let ((count 1)
+	(pos 0))
+    (while (and (string-match regexp string pos) (<= count limit))
+      (setq count (1+ count)
+	    pos (match-end 0)))
+    count))
+
+;;;%Matcher
+(defun completer-matches (string choices delimiters any)
+    "Return STRING's matches in CHOICES using DELIMITERS and wildcard
+ANY to segment the strings."
+    (let* ((regexp (concat "[" delimiters "]"))
+	   (from nil)
+	   (to 0)
+	   (pattern nil)
+	   (len (length string))
+	   (matches nil)
+	   sub sublen choice word wordlen pat)
+      ;; Segment pattern
+      (while (< (or from 0) len)
+	(setq to (or (string-match regexp string (if from (1+ from))) len))
+	(if (eq (elt string (or from 0)) completer-any-delimiter)
+	    (setq sub (substring string (if from (1+ from) 0) to)
+		  sublen (- (length sub)))
+	    (setq sub (substring string (or from 0) to)
+		  sublen (length sub)))
+	(setq pattern (cons (cons sub sublen) pattern)
+	      from to))
+      (setq pattern (reverse pattern))
+      ;; Find choices that match patterns
+      (setq regexp (concat "[" delimiters "]"))
+      (while choices
+	(setq choice (car choices)
+	      word pattern 
+	      from 0)
+	(while (and word from
+		    (let* (begin end)
+		      (if (< (setq wordlen (cdr (setq pat (car word)))) 0)
+			  (setq begin (1+ from)
+				end (+ begin (- wordlen)))
+			  (setq begin from
+				end (+ begin wordlen)))
+		      (and (<= end (length choice))
+			   (or (zerop wordlen)
+			       (string-equal 
+				(car pat)
+				(substring choice begin end))))))
+	  (setq from (string-match regexp choice 
+				   (if (and (zerop from) (zerop wordlen))
+				       from
+				       (1+ from)))
+		word (cdr word)))
+	(if (not word) (setq matches (cons choice matches)))
+	(setq choices (cdr choices)))
+      matches))
+
+;;;
+(defun completer-choice (string choices delimiters use-words)
+  "Return the best match of STRING in CHOICES with DELIMITERS between
+words and T if it is unique.  A match is unique if it is the only
+possibility or when USE-WORDS the only possibility with the same
+number of words.  The shortest string of multiple possiblities will be
+the best match."
+  (or (if (null (cdr choices)) (cons (car choices) t))
+      (let* ((regexp (concat "[^" delimiters "]*[" delimiters "]"))
+	     (words (if use-words (completer-words regexp string)))
+	     (choice choices)
+	     (unique-p nil)
+	     (match nil)
+	     (match-count nil)
+	     (match-len 1000))
+	(while choice
+	  (let* ((current (car choice))
+		 (length (length current)))
+	    (if match-count
+		(if (= (completer-words regexp current words) words)
+		    (progn
+		      (setq unique-p nil)
+		      (if (< length match-len)
+			  (setq match current
+				match-len length))))
+		(if (and use-words 
+			 (= (completer-words regexp current words) words))
+		    (setq match current
+			  match-len length
+			  match-count t
+			  unique-p t)
+		    (if (< length match-len)
+			(setq match current
+			      match-len length)))))
+	  (setq choice (cdr choice)))
+	(cons match unique-p))))
+
+;;;%Completer
+;;;%%Utilities
+(defun completer-region (delimiters)
+  "Return the completion region bounded by characters in DELIMITERS
+for the current buffer assuming that point is in it."
+  (cons (save-excursion (skip-chars-backward delimiters) (point))
+	(save-excursion (skip-chars-forward delimiters) (point))))
+	 
+;;;
+(defun completer-last-component (string)
+  "Return the start of the last filename component in STRING."
+  (let ((last (1- (length string)) )
+	(match 0)
+	(end 0))
+    (while (and (setq match (string-match "/" string end)) (< match last))
+      (setq end (1+ match)))
+    end))
+
+;;;
+(defun completer-match-record (string matches delimiters any dir mode)
+  "Return (match lcs choices unique) for STRING in MATCHES with
+DELIMITERS or ANY wildcards and DIR if a filename when in MODE."
+  (let ((pattern (if dir
+		     (substring string (completer-last-component string))
+		     string)))
+    (setq matches (completer-matches pattern matches delimiters any))
+    (if (cdr matches)
+	(let ((match
+	       (if (not completer-exact)
+		   (completer-choice
+		    pattern matches delimiters completer-use-words)))
+	      (lcs (concat dir (try-completion "" (mapcar 'list matches)))))
+	  (list (if match (concat dir (car match)))
+		lcs
+		matches (cdr match)))
+      (if matches 
+	  (let ((match (concat dir (car matches))))
+	    (list match match matches t))
+	(list nil nil nil nil)))))
+
+;;;%%Complete file
+(defun completer-extension-regexp (extensions)
+  "Return a regexp that matches any of EXTENSIONS."
+  (let ((regexp "\\("))
+    (while extensions
+      (setq regexp (concat regexp (car extensions)
+			   (if (cdr extensions) "\\|"))
+	    extensions (cdr extensions)))
+    (concat regexp "\\)$")))
+
+;;;
+(defun completer-flush ()
+  "Flush completer's pathname cache."
+  (interactive)
+  (setq completer-path-cache nil))
+
+;;;
+(defun completer-cache (path pred words any mode)
+  "Check to see if PATH is in path cache with PRED, WORDS, ANY and
+MODE."
+  (let* ((last nil)
+	 (ptr completer-path-cache)
+	 (size 0) 
+	 (result nil))
+    (if completer-use-cache
+	(while ptr
+	  (let ((current (car (car ptr))))
+	    (if (string-equal current path)
+		(progn
+		  (if last
+		      (progn
+			(rplacd last (cdr ptr))
+			(rplacd ptr completer-path-cache)
+			(setq completer-path-cache ptr)))
+		  (setq result (cdr (car ptr))
+			ptr nil))
+	      (if (cdr ptr) (setq last ptr))
+	      (setq size (1+ size)
+		    ptr (cdr ptr))))))
+    (or result
+	(let* ((choices 
+		(completer path 'read-file-name-internal pred words any
+			   mode t)))
+	  (if (and (or (car (cdr (cdr (cdr choices))))
+		       (string= path (car choices)))
+		   (eq (elt (car choices) (1- (length (car choices)))) ?/))
+	      (progn 
+		(if (>= size completer-cache-size) (rplacd last nil))
+		(setq completer-path-cache 
+		      (cons (cons path choices) completer-path-cache))))
+	  choices))))
+
+;;;
+(defun completer-file (string pred words any mode)
+  "Return (match common-substring matches unique-p) for STRING using
+read-file-name-internal for choices that pass PRED using WORDS to
+delimit words.  Optional ANY is a delimiter that matches any of the
+delimiters in WORD.  If optional MODE is nil or 'help then possible
+matches will always be returned."
+  (let* ((case-fold-search completion-ignore-case)
+	 (last (and (eq mode 'exit-ok) (completer-last-component string)))
+	 (position
+	  ;; Special hack for CMU RFS filenames
+	  (if (string-match "^/\\.\\./[^/]*/" string)
+	      (match-end 0)
+	      (string-match "[^~/]" string)))
+	 (new (substring string 0 position))
+	 (user (if (string= new "~")
+		   (setq new (file-name-directory (expand-file-name new)))))
+	 (words (concat words "/"))
+	 (len (length string))
+	 (choices nil)
+	 end
+	 (old-choices (list nil nil nil nil)))
+    (while position
+      (let* ((begin (string-match "/" string position))
+	     (exact-p nil))
+	(setq end (if begin (match-end 0))
+	      choices
+	      ;; Ends with a /, so check files in directory
+	      (if (and (memq mode '(nil help)) (= position len))
+		  (completer-match-record 
+		   ""
+		   ;; This assumes that .. and . come at the end
+		   (let* ((choices
+			   (all-completions new 'read-file-name-internal))
+			  (choicep choices))
+		     (if (string= (car choicep) "../")
+			 (cdr (cdr choicep))
+			 (while (cdr choicep)
+			   (if (string= (car (cdr choicep)) "../")
+			       (rplacd choicep nil))
+			   (setq choicep (cdr choicep)))
+			 choices))
+		   words any new mode)
+		  (if (eq position last)
+		      (let ((new (concat new (substring string position))))
+			(list new new nil t))
+		      (let ((component (substring string position end)))
+			(if (and end
+				 (string-match completer-file-skip component))
+			    ;; Assume component is complete
+			    (list (concat new component) 
+				  (concat new component)
+				  nil t)
+			    (completer-cache
+			     (concat new component)
+			     pred words any mode))))))
+	;; Keep going if unique or we match exactly
+	(if (or (car (cdr (cdr (cdr choices))))
+		(setq exact-p
+		      (string= (concat new (substring string position end))
+			       (car choices))))
+	    (setq old-choices
+		  (let* ((lcs (car (cdr choices)))
+			 (matches (car (cdr (cdr choices))))
+			 (slash (and lcs (string-match "/$" lcs))))
+		    (list nil
+			  (if slash (substring lcs 0 slash) lcs)
+			  (if (and (cdr matches) 
+				   (or (eq mode 'help) (not exact-p)))
+			      matches)
+			  nil))
+		  new (car choices)
+		  position end)
+	    ;; Its ok to not match user names because they may be in
+	    ;; different root directories
+	    (if (and (= position 1) (= (elt string 0) ?~))
+		(setq new (substring string 0 end)
+		      choices (list new new (list new) t)
+		      user nil
+		      position end)
+		(setq position nil)))))
+    (if (not (car choices))
+	(setq choices old-choices))
+    (if (and (car choices)
+	     (not (eq mode 'help))
+	     (not (car (cdr (cdr (cdr choices))))))
+	;; Try removing completion ignored extensions
+	(let* ((extensions
+		(completer-extension-regexp completion-ignored-extensions))
+	       (choiceb (car (cdr (cdr choices))))
+	       (choicep choiceb)
+	       (isext nil)
+	       (noext nil))
+	  (while choicep
+	    (if (string-match extensions (car choicep))
+		(setq isext t)
+		(setq noext t))
+	    (if (and isext noext)
+		;; There are matches besides extensions
+		(setq choiceb (completer-deleter extensions choiceb)
+		      choicep nil)
+		(setq choicep (cdr choicep))))
+	  (if (and isext noext)
+	      (setq choices
+		    (completer-match-record 
+		     (if end (substring string end) "")
+		     choiceb words any
+		     (file-name-directory (car (cdr choices)))
+		     mode)))))
+    (if user
+	(let ((match (car choices))
+	      (lcs (car (cdr choices)))
+	      (len (length user)))
+	  (setq choices
+		(cons (if match (concat "~" (substring match len)))
+		      (cons (if lcs (concat "~" (substring lcs len)))
+			    (cdr (cdr choices)))))))
+    choices))
+
+;;;%Exported program interface
+;;;%%Completer
+(defun completer (string table pred words
+			 &optional any mode file-p)
+  "Return (match common-substring matches unique-p) for STRING in
+TABLE for choices that pass PRED using WORDS to delimit words.  If the
+flag completer-complete-filenames is T and the table is
+read-file-name-internal, then filename components will be individually
+expanded.  Optional ANY is a delimiter that can match any delimiter in
+WORDS.  Optional MODE is nil for complete, 'help for help and 'exit
+for exit."
+  (if (and (stringp completer-string) 
+	   (string= string completer-string)
+	   (eq table completer-table)
+	   (eq pred completer-pred)
+	   (not file-p)
+	   (or (eq mode completer-mode)
+	       (not (memq table '(read-file-name-internal
+				  read-directory-name-internal)))))
+      completer-result
+      (setq 
+       completer-string ""
+       completer-table table
+       completer-pred pred
+       completer-mode mode
+       completer-result
+       (if (and completer-complete-filenames
+		(not file-p) (eq table 'read-file-name-internal))
+	   (completer-file string pred words any mode)
+	   (let* ((file-p (or file-p (eq table 'read-file-name-internal)))
+		  (case-fold-search completion-ignore-case)
+		  (pattern (concat "[" words "]"))
+		  (component (if file-p (completer-last-component string)))
+		  (dir (if component (substring string 0 component)))
+		  (string (if dir (substring string component) string))
+		  (has-words (or (string-match pattern string)
+				 (length string))))
+	     (if (and file-p (string-match "^\\$" string))
+		 ;; Handle environment variables
+		 (let ((match
+			(getenv (substring string 1 
+					   (string-match "/" string)))))
+		   (if match (setq match (concat match "/")))
+		   (list match match (list match) match))
+		 (let* ((choices
+			 (all-completions 
+			  (concat dir (substring string 0 has-words))
+			  table pred))
+			(regexp (completer-regexp string words any)))
+		   (if choices
+		       (completer-match-record 
+			string 
+			(completer-deleter regexp choices t) 
+			words any dir mode)
+		       (list nil nil nil nil))))))
+       completer-string string)
+      completer-result))
+
+;;;%%Display choices
+(defun completer-display-choices (choices &optional match message end
+					  display)
+  "Display the list of possible CHOICES with optional MATCH, MESSAGE,
+END and DISPLAY.  If MATCH is non-nil, it will be flagged as the best
+guess.  If there are no choices, display MESSAGE.  END is where to put
+temporary messages.  If DISPLAY is present then it will be called on
+each possible completion and should return a string."
+  (if choices
+      (with-output-to-temp-buffer " *Completions*"
+	(if (cdr choices) 
+	    (display-completion-list
+	     (sort
+	      (if display
+		  (let ((old choices)
+			(new nil))
+		    (while old
+		      (setq new (cons (funcall display (car old)) new)
+			    old (cdr old)))
+		    new)
+		(copy-sequence choices))
+	      (function (lambda (x y)
+			  (string-lessp (or (car-safe x) x)
+					(or (car-safe y) y)))))))
+	(if match
+	    (save-excursion
+	      (set-buffer " *Completions*")
+	      (goto-char (point-min))
+	      (insert "Guess = " match (if (cdr choices) ", " "")))))
+      (beep)
+      (completer-message (or message " (No completions)") end)))
+
+;;;%%Goto
+(defun completer-goto (match lcs choices unique delimiters words 
+			     &optional mode display)
+  "MATCH is the best match, LCS is the longest common substring of all
+of the matches.  CHOICES is a list of the possibilities, UNIQUE
+indicates if MATCH is unique.  DELIMITERS are possible bounding
+characters for the completion region.  WORDS are the characters that
+delimit the words for partial matches.  Replace the region bounded by
+delimiters with the match if unique and the lcs otherwise unless
+optional MODE is 'help.  Then go to the part of the string that
+disambiguates choices using WORDS to separate words and display the
+possibilities if the string was not extended.  If optional DISPLAY is
+present then it will be called on each possible completion and should
+return a string."
+  (setq completer-message nil)
+  (let* ((region (completer-region delimiters))
+	 (start (car region))
+	 (end (cdr region))
+	 (string (buffer-substring start end))
+	 (file-p (string-match "[^ ]*\\(~\\|/\\|$\\)" string))
+	 (no-insert (eq mode 'help))
+	 (message t)
+	 (new (not (string= (buffer-substring start (point)) lcs))))
+    (if unique
+	(if no-insert
+	    (progn
+	      (goto-char end)
+	      (completer-display-choices choices match nil end display))
+	    (if (string= string match)
+		(if (not file-p) 
+		    (progn (goto-char end)
+			   (completer-message " (Sole completion)" end)))
+		(completer-insert match delimiters)))
+	;;Not unique
+	(if lcs
+	    (let* ((regexp 
+		    (concat "[" words (if file-p "/") "]"))
+		   (words (completer-words regexp lcs))
+		   point)
+	      ;; Go to where its ambiguous
+	      (goto-char start)
+	      (if (not no-insert)
+		  (progn 
+		    (insert lcs)
+		    (setq completer-last-pattern 
+			  (list string delimiters (current-buffer) start)
+			  start (point)
+			  end (+ end (length lcs)))))
+	      ;; Skip to the first delimiter in the original string
+	      ;; beyond the ambiguous point and keep from there on
+	      (if (re-search-forward regexp end 'move words)
+		  (progn
+		    (if (and (not no-insert) match)
+			(let ((delimiter
+			       (progn
+				 (string-match lcs match)
+				 (substring match (match-end 0)
+					    (1+ (match-end 0))))))
+			  (if (string-match regexp delimiter)
+			      (insert delimiter))))
+		    (forward-char -1)))
+	      (if (not no-insert) 
+		  (progn
+		    (setq end (- end (- (point) start)))
+		    (delete-region start (point))))))
+	(if choices
+	    (if (or no-insert (not new))
+		(completer-display-choices choices match nil end display))
+	    (if file-p 
+		(progn 
+		  (if (not (= (point) end)) (forward-char 1))
+		  (if (not (save-excursion (re-search-forward "/" end t)))
+		      (goto-char end))))
+	    (if message
+		(progn
+		  (beep)
+		  (completer-message (if no-insert 
+					 " (No completions)"
+					 " (No match)")
+				     end)))))))	    
+
+;;;%Exported buffer interface
+;;;%%Complete and go
+(defun completer-complete-goto (delimiters words table pred 
+					   &optional no-insert display)
+  "Complete the string bound by DELIMITERS using WORDS to bound words
+for partial matches in TABLE with PRED and then insert the longest
+common substring unless optional NO-INSERT and go to the point of
+ambiguity.  If optional DISPLAY, it will be called on each match when
+possible completions are shown and should return a string."
+  (let* ((region (completer-region delimiters)))
+    (apply 'completer-goto 
+	   (append (completer (buffer-substring (car region) (cdr region))
+			      table pred words completer-any-delimiter
+			      no-insert)
+		  (list delimiters words no-insert display)))))
+
+;;;%%Undo
+(defun completer-insert (match delimiters &optional buffer undo)
+  "Replace the region bounded with characters in DELIMITERS by MATCH
+and save it so that it can be restored by completer-undo."
+  (let* ((region (completer-region delimiters))
+	 (start (car region))
+	 (end (cdr region)))
+    (if (and undo (or (not (= start undo)) 
+		      (not (eq (current-buffer) buffer))))
+	(error "No previous pattern")
+	(setq completer-last-pattern (list (buffer-substring start end) 
+					   delimiters
+					   (current-buffer)
+					   start))
+	(delete-region start end)
+	(goto-char start)
+	(insert match))))
+
+;;;
+(defun completer-undo ()
+  "Swap the last expansion and the last match pattern."
+  (interactive)
+  (if completer-last-pattern
+      (apply 'completer-insert completer-last-pattern)
+      (error "No previous pattern")))
+
+;;;%Minibuffer specific code
+;;;%%Utilities
+(defun completer-minibuf-string ()
+  "Remove dead filename specs from the minibuffer as delimited by //
+or ~ or $ and return the resulting string."
+  (save-excursion
+    (goto-char (point-max))
+    (if (and (eq minibuffer-completion-table 'read-file-name-internal)
+	     (re-search-backward "//\\|/~\\|.\\$" nil t))
+	(delete-region (point-min) (1+ (point))))
+    (buffer-substring (point-min) (point-max))))
+
+;;;
+(defun completer-minibuf-exit ()
+  "Exit and clear pattern."
+  (interactive)
+  (setq completer-last-pattern nil)
+  (exit-minibuffer))
+
+;;;
+(defun completer-new-cmd (cmd)
+  "Return T if we can't execute the old minibuffer version of CMD."
+  (if (or completer-disable
+	  (let ((string (completer-minibuf-string)))
+	    (or
+	     (not (string-match
+		   (concat "[" completer-words "/~]")
+		   string))
+	      (condition-case ()
+		  (let ((completion
+			 (try-completion string
+					 minibuffer-completion-table
+					 minibuffer-completion-predicate)))
+		    (if (eq minibuffer-completion-table
+			    'read-file-name-internal)
+			;; Directories complete as themselves
+			(and completion
+			     (or (not (string= string completion))
+				 (file-exists-p completion)))
+			completion))
+		(error nil)))))
+      (progn
+	(funcall cmd)
+	nil)
+      t))
+
+;;;
+(defun completer-minibuf (&optional mode)
+  "Partial completion of minibuffer expressions.  Optional MODE is
+'help for help and 'exit for exit.
+
+If what has been typed so far matches any possibility normal
+completion will be done.  Otherwise, the string is considered to be a
+pattern with words delimited by the characters in
+completer-words.  If completer-exact is T, the best match will be
+the shortest one with the same number of words as the pattern if
+possible and otherwise the shortest matching expression.  If called
+with a prefix, caching will be temporarily disabled.
+
+Examples:
+a-f     auto-fill-mode
+r-e     rmail-expunge
+b--d    *begining-of-defun or byte-recompile-directory
+by  d   *byte-recompile-directory if completer-any-delimiter is \" \"
+~/i.e   *~/ilisp.el or ~/il-el.el or ~/ilisp.elc
+/u/mi/  /usr/misc/"
+  (interactive)
+  (append
+   (let ((completer-use-cache (not (or (not completer-use-cache)
+				       current-prefix-arg))))
+     (completer (completer-minibuf-string)
+		minibuffer-completion-table
+		minibuffer-completion-predicate
+		completer-words
+		completer-any-delimiter
+		mode))
+   (list "^" completer-words mode)))
+
+;;;%%Commands
+(defun completer-toggle ()
+  "Turn partial completion on or off."
+  (interactive)
+  (setq completer-disable (not completer-disable))
+  (message (if completer-disable 
+	       "Partial completion OFF"
+	       "Partial completion ON")))
+
+;;;
+(defvar completer-old-help
+  (lookup-key minibuffer-local-must-match-map "?")
+  "Old binding of ? in minibuffer completion map.")
+(defun completer-help ()
+  "Partial completion minibuffer-completion-help.  
+See completer-minibuf for more information."
+  (interactive)
+  (if (completer-new-cmd completer-old-help)
+      (apply 'completer-goto (completer-minibuf 'help))))
+
+;;;
+(defvar completer-old-completer
+  (lookup-key minibuffer-local-must-match-map "\t")
+  "Old binding of TAB in minibuffer completion map.")
+(defun completer-complete ()
+  "Partial completion minibuffer-complete.
+See completer-minibuf for more information."
+  (interactive)
+  (if (completer-new-cmd completer-old-completer)
+      (apply 'completer-goto (completer-minibuf))))
+
+;;;
+(defvar completer-old-word
+  (lookup-key minibuffer-local-must-match-map " ")
+  "Old binding of SPACE in minibuffer completion map.")
+(defun completer-word ()
+  "Partial completion minibuffer-complete.
+See completer-minibuf for more information."
+  (interactive)
+  (if (eq completer-any-delimiter ?\ )
+      (insert ?\ )
+      (if (completer-new-cmd completer-old-word)
+	  (apply 'completer-goto (completer-minibuf)))))
+
+;;; 
+(defvar completer-old-exit
+  (lookup-key minibuffer-local-must-match-map "\n")
+  "Old binding of RET in minibuffer completion map.")
+(defun completer-exit ()
+  "Partial completion minibuffer-complete-and-exit.
+See completer-minibuf for more information."
+  (interactive)
+  (if (completer-new-cmd completer-old-exit)
+      (let* ((completions (completer-minibuf 'exit))
+	     (match (car completions))
+	     (unique-p (car (cdr (cdr (cdr completions))))))
+	(apply 'completer-goto completions)
+	(if unique-p
+	    (completer-minibuf-exit)
+	    (if match
+		(progn (completer-insert match "^")
+		       (if minibuffer-completion-confirm
+			   (completer-message " (Confirm)")
+			   (completer-minibuf-exit)))
+		(if (not completer-message) (beep)))))))
+
+;;;
+(defun completer-match-exit ()
+  "Exit the minibuffer with the current best match."
+  (interactive)
+  (let* ((completions (completer-minibuf 'exit))
+	 (guess (car completions)))
+    (if (not guess) 
+	;; OK if last filename component doesn't match
+	(setq completions (completer-minibuf 'exit-ok)
+	      guess (car completions)))
+    (if guess
+	(progn
+	  (goto-char (point-min))
+	  (insert guess)
+	  (delete-region (point) (point-max))
+	  (exit-minibuffer))
+	(apply 'completer-goto completions))))
+
+;;;%%Keymaps
+(define-key minibuffer-local-completion-map "\C-_"  'completer-undo)
+(define-key minibuffer-local-completion-map "\t"    'completer-complete)
+(define-key minibuffer-local-completion-map " "     'completer-word)
+(define-key minibuffer-local-completion-map "?"     'completer-help)
+(define-key minibuffer-local-completion-map "\n"    'completer-minibuf-exit)
+(define-key minibuffer-local-completion-map "\r"    'completer-minibuf-exit)
+(define-key minibuffer-local-completion-map "\M-\n" 'completer-match-exit)
+(define-key minibuffer-local-completion-map "\M-\r" 'completer-match-exit)
+
+(define-key minibuffer-local-must-match-map "\C-_"  'completer-undo)
+(define-key minibuffer-local-must-match-map "\t"    'completer-complete)
+(define-key minibuffer-local-must-match-map " "     'completer-word)
+(define-key minibuffer-local-must-match-map "\n"    'completer-exit)
+(define-key minibuffer-local-must-match-map "\r"    'completer-exit)
+(define-key minibuffer-local-must-match-map "?"     'completer-help)
+(define-key minibuffer-local-must-match-map "\M-\n" 'completer-match-exit)
+(define-key minibuffer-local-must-match-map "\M-\r" 'completer-match-exit)
+
+;;;%comint 
+(defun completer-comint-dynamic-list-completions (completions)
+  "List in help buffer sorted COMPLETIONS.
+Typing SPC flushes the help buffer."
+  (completer-comint-dynamic-complete-1 nil 'help))
+
+(defun completer-comint-dynamic-complete-filename ()
+  "Dynamically complete the filename at point."
+  (completer-comint-dynamic-complete-1 nil t))
+
+;;;
+(defun completer-comint-dynamic-complete-1 (&optional undo mode)
+  "Complete the previous filename or display possibilities if done
+twice in a row.  If called with a prefix, undo the last completion."
+  (interactive "P")
+  (if undo
+      (completer-undo)
+    ;; added by jwz: don't cache completions in shell buffer!
+    (setq completer-string nil)
+    (let ((conf (current-window-configuration)));; lemacs change
+      (completer-complete-goto 
+       "^ \t\n\""
+       completer-words
+       'read-file-name-internal
+       default-directory
+       mode)
+      ;; lemacs change
+      (if (eq mode 'help) (comint-restore-window-config conf))
+      )))
+;(fset 'comint-dynamic-complete 'completer-comint-dynamic-complete)
+(fset 'comint-dynamic-complete-filename
+      'completer-comint-dynamic-complete-filename)
+(fset 'comint-dynamic-list-completions 
+      'completer-comint-dynamic-list-completions)
+
+;;; Set the functions again if comint is loaded
+(setq comint-load-hook 
+      (cons (function (lambda ()
+;;	      (fset 'comint-dynamic-complete 
+;;		    'completer-comint-dynamic-complete)
+			(fset 'comint-dynamic-complete-filename
+			      'completer-comint-dynamic-complete-filename)
+	      (fset 'comint-dynamic-list-completions 
+		    'completer-comint-dynamic-list-completions)))
+	    (if (and (boundp 'comint-load-hook) comint-load-hook)
+		(if (consp comint-load-hook) 
+		    (if (eq (car comint-load-hook) 'lambda)
+			(list comint-load-hook)
+			comint-load-hook)
+		    (list comint-load-hook)))))
+
+;;;%lisp-complete-symbol
+(defun lisp-complete-symbol (&optional mode)
+  "Perform partial completion on Lisp symbol preceding point.  That
+symbol is compared against the symbols that exist and any additional
+characters determined by what is there are inserted.  If the symbol
+starts just after an open-parenthesis, only symbols with function
+definitions are considered.  Otherwise, all symbols with function
+definitions, values or properties are considered.  If called with a
+negative prefix, the last completion will be undone."
+  (interactive "P")
+  (if (< (prefix-numeric-value mode) 0)
+      (completer-undo)
+      (let* ((end (save-excursion (skip-chars-forward "^ \t\n)]}\"") (point)))
+	     (beg (save-excursion
+		    (backward-sexp 1)
+		    (while (= (char-syntax (following-char)) ?\')
+		      (forward-char 1))
+		    (point)))
+	     (pattern (buffer-substring beg end))
+	     (predicate
+	      (if (eq (char-after (1- beg)) ?\()
+		  'fboundp
+		  (function (lambda (sym)
+		    (or (boundp sym) (fboundp sym)
+			(symbol-plist sym))))))
+	     (completion (try-completion pattern obarray predicate)))
+	   (cond ((eq completion t))
+	      ((null completion)
+	       (completer-complete-goto
+		"^ \t\n\(\)[]{}'`" completer-words
+		obarray predicate 
+		nil
+		(if (not (eq predicate 'fboundp))
+		    (function (lambda (choice)
+		      (if (fboundp (intern choice))
+			  (list choice " <f>")
+			  choice))))))
+	      ((not (string= pattern completion))
+	       (delete-region beg end)
+	       (insert completion))
+	      (t
+	       (message "Making completion list...")
+	       (let ((list (all-completions pattern obarray predicate)))
+		 (or (eq predicate 'fboundp)
+		     (let (new)
+		       (while list
+			 (setq new (cons (if (fboundp (intern (car list)))
+					     (list (car list) " <f>")
+					     (car list))
+					 new))
+			 (setq list (cdr list)))
+		       (setq list (nreverse new))))
+		 (with-output-to-temp-buffer "*Help*"
+		   (display-completion-list
+		    (sort list (function (lambda (x y)
+					   (string-lessp
+					    (or (car-safe x) x)
+					    (or (car-safe y) y))))))))
+	       (message "Making completion list...%s" "done"))))))
+
+;;;%Hooks
+(provide 'completer)
+(run-hooks 'completer-load-hook)
+