changeset 55434:f88632e54afb

2004-05-08 John Wiegley <johnw@newartisans.com> * iswitchb.el (iswitchb-use-virtual-buffers): Added support for "virtual buffers" (off by default), which makes it possible to switch to the buffers of recently files. When a buffer name search fails, and this option is on, iswitchb will look at the list of recently visited files, and permit matching against those names. When the user hits RET on a match, it will revisit that file. (iswitchb-read-buffer): Added two optional arguments, which makes isearchb.el possible. (iswitchb-completions, iswitchb-set-matches, iswitchb-prev-match, iswitchb-next-match): Added support for virtual buffers.
author John Wiegley <johnw@newartisans.com>
date Sat, 08 May 2004 13:00:52 +0000
parents e0a9c86fa070
children 67d5cadcfc5f
files lisp/iswitchb.el
diffstat 1 files changed, 100 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/iswitchb.el	Sat May 08 12:52:45 2004 +0000
+++ b/lisp/iswitchb.el	Sat May 08 13:00:52 2004 +0000
@@ -307,6 +307,20 @@
   :type '(choice (const :tag "Show all" nil) integer)
   :group 'iswitchb)
 
+(defcustom iswitchb-use-virtual-buffers nil
+  "*If non-nil, refer to past buffers when none match.
+This feature relies upon the `recentf' package, which will be
+enabled if this variable is configured to a non-nil value."
+  :type 'boolean
+  :require 'recentf
+  :set (function
+	(lambda (sym value)
+	  (recentf-mode value)
+	  (set sym value)))
+  :group 'iswitchb)
+
+(defvar iswitchb-virtual-buffers nil)
+
 (defcustom iswitchb-cannot-complete-hook 'iswitchb-completion-help
   "*Hook run when `iswitchb-complete' can't complete any more.
 The most useful values are `iswitchb-completion-help', which pops up a
@@ -571,12 +585,18 @@
 		 (iswitchb-possible-new-buffer buf)))
 	   ))))
 
-(defun iswitchb-read-buffer (prompt &optional default require-match)
+(defun iswitchb-read-buffer (prompt &optional default require-match
+				    start matches-set)
   "Replacement for the built-in `read-buffer'.
 Return the name of a buffer selected.
-PROMPT is the prompt to give to the user.  DEFAULT if given is the default
-buffer to be selected, which will go to the front of the list.
-If REQUIRE-MATCH is non-nil, an existing-buffer must be selected."
+PROMPT is the prompt to give to the user.
+DEFAULT if given is the default buffer to be selected, which will
+go to the front of the list.
+If REQUIRE-MATCH is non-nil, an existing-buffer must be selected.
+If START is a string, the selection process is started with that
+string.
+If MATCHES-SET is non-nil, the buflist is not updated before
+the selection process begins.  Used by isearchb.el."
   (let
       (
        buf-sel
@@ -589,14 +609,15 @@
 
     (iswitchb-define-mode-map)
     (setq iswitchb-exit nil)
-    (setq iswitchb-rescan t)
-    (setq iswitchb-text "")
     (setq iswitchb-default
 	  (if (bufferp default)
 	      (buffer-name default)
 	    default))
-    (iswitchb-make-buflist iswitchb-default)
-    (iswitchb-set-matches)
+    (setq iswitchb-text (or start ""))
+    (unless matches-set
+      (setq iswitchb-rescan t)
+      (iswitchb-make-buflist iswitchb-default)
+      (iswitchb-set-matches))
     (let
 	((minibuffer-local-completion-map iswitchb-mode-map)
 	 ;; Record the minibuffer depth that we expect to find once
@@ -605,32 +626,41 @@
 	 (iswitchb-require-match require-match))
       ;; prompt the user for the buffer name
       (setq iswitchb-final-text (completing-read
-				 prompt	;the prompt
+				 prompt		  ;the prompt
 				 '(("dummy" . 1)) ;table
-				 nil	;predicate
-				 nil	;require-match [handled elsewhere]
-				 nil	;initial-contents
+				 nil		  ;predicate
+				 nil ;require-match [handled elsewhere]
+				 start	;initial-contents
 				 'iswitchb-history)))
     (if (and (not (eq iswitchb-exit 'usefirst))
 	     (get-buffer iswitchb-final-text))
 	;; This happens for example if the buffer was chosen with the mouse.
-	(setq iswitchb-matches (list iswitchb-final-text)))
+	(setq iswitchb-matches (list iswitchb-final-text)
+	      iswitchb-virtual-buffers nil))
+
+    ;; If no buffer matched, but a virtual buffer was selected, visit
+    ;; that file now and act as though that buffer had been selected.
+    (if (and iswitchb-virtual-buffers
+	     (not (iswitchb-existing-buffer-p)))
+	(let ((virt (car iswitchb-virtual-buffers)))
+	  (find-file-noselect (cdr virt))
+	  (setq iswitchb-matches (list (car virt))
+		iswitchb-virtual-buffers nil)))
 
     ;; Handling the require-match must be done in a better way.
-    (if (and require-match (not (iswitchb-existing-buffer-p)))
+    (if (and require-match
+	     (not (iswitchb-existing-buffer-p)))
 	(error "Must specify valid buffer"))
 
-    (if (or
-	 (eq iswitchb-exit 'takeprompt)
-	 (null iswitchb-matches))
+    (if (or (eq iswitchb-exit 'takeprompt)
+	    (null iswitchb-matches))
 	(setq buf-sel iswitchb-final-text)
       ;; else take head of list
       (setq buf-sel (car iswitchb-matches)))
 
     ;; Or possibly choose the default buffer
     (if  (equal iswitchb-final-text "")
-	(setq buf-sel
-	      (car iswitchb-matches)))
+	(setq buf-sel (car iswitchb-matches)))
 
     buf-sel))
 
@@ -731,18 +761,29 @@
   (setq iswitchb-exit 'findfile)
   (exit-minibuffer))
 
+(eval-when-compile
+  (defvar recentf-list))
+
 (defun iswitchb-next-match ()
   "Put first element of `iswitchb-matches' at the end of the list."
   (interactive)
   (let ((next  (cadr iswitchb-matches)))
-    (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist next))
+    (if (and (null next) iswitchb-virtual-buffers)
+	(setq recentf-list
+	      (iswitchb-chop recentf-list
+			     (cdr (cadr iswitchb-virtual-buffers))))
+      (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist next)))
     (setq iswitchb-rescan t)))
 
 (defun iswitchb-prev-match ()
   "Put last element of `iswitchb-matches' at the front of the list."
   (interactive)
   (let ((prev  (car (last iswitchb-matches))))
-    (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist prev))
+    (if (and (null prev) iswitchb-virtual-buffers)
+	(setq recentf-list
+	      (iswitchb-chop recentf-list
+			     (cdr (car (last iswitchb-virtual-buffers)))))
+      (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist prev)))
     (setq iswitchb-rescan t)))
 
 (defun iswitchb-chop (list elem)
@@ -834,7 +875,8 @@
       (setq iswitchb-matches
 	    (let* ((buflist iswitchb-buflist))
 	      (iswitchb-get-matched-buffers iswitchb-text iswitchb-regexp
-					    buflist)))))
+					    buflist))
+	    iswitchb-virtual-buffers nil)))
 
 (defun iswitchb-get-matched-buffers (regexp
 				     &optional string-format buffer-list)
@@ -1188,6 +1230,10 @@
 		   contents
 		   (not minibuffer-completion-confirm)))))))
 
+(eval-when-compile
+  (defvar most-len)
+  (defvar most-is-exact))
+
 (defun iswitchb-output-completion (com)
   (if (= (length com) most-len)
       ;; Most is one exact match,
@@ -1221,6 +1267,35 @@
 			     first)
 	  (setq comps  (cons first (cdr comps)))))
 
+    ;; If no buffers matched, and virtual buffers are being used, then
+    ;; consult the list of past visited files, to see if we can find
+    ;; the file which the user might thought was still open.
+    (when (and iswitchb-use-virtual-buffers (null comps)
+	       recentf-list)
+      (setq iswitchb-virtual-buffers nil)
+      (let ((head recentf-list) name)
+	(while head
+	  (if (and (setq name (file-name-nondirectory (car head)))
+		   (string-match (if iswitchb-regexp
+				     iswitchb-text
+				   (regexp-quote iswitchb-text)) name)
+		   (null (get-file-buffer (car head)))
+		   (not (assoc name iswitchb-virtual-buffers))
+		   (not (iswitchb-ignore-buffername-p name))
+		   (file-exists-p (car head)))
+	      (setq iswitchb-virtual-buffers
+		    (cons (cons name (car head))
+			  iswitchb-virtual-buffers)))
+	  (setq head (cdr head)))
+	(setq iswitchb-virtual-buffers (nreverse iswitchb-virtual-buffers)
+	      comps (mapcar 'car iswitchb-virtual-buffers))
+	(let ((comp comps))
+	  (while comp
+	    (put-text-property 0 (length (car comp))
+			       'face 'font-lock-builtin-face
+			       (car comp))
+	    (setq comp (cdr comp))))))
+
     (cond ((null comps) (format " %sNo match%s"
 				open-bracket-determined
 				close-bracket-determined))
@@ -1255,10 +1330,9 @@
 		  (most nil)
 		  (most-len (length most))
 		  most-is-exact
-		  (alternatives (if most
-				    (mapconcat 'iswitchb-output-completion
-					       comps ",")
-				  (mapconcat 'identity comps ","))))
+		  (alternatives
+		   (mapconcat (if most 'iswitchb-output-completion
+				'identity) comps ",")))
 
 	     (concat