*** empty log message ***
[bpt/emacs.git] / lisp / iswitchb.el
CommitLineData
6c56c80b 1;;; iswitchb.el --- switch between buffers using substrings
962a4216 2
0d30b337
TTN
3;; Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004,
4;; 2005 Free Software Foundation, Inc.
962a4216 5
b2537dfa
RS
6;; Author: Stephen Eglen <stephen@gnu.org>
7;; Maintainer: Stephen Eglen <stephen@gnu.org>
19db4308 8;; Keywords: completion convenience
183040ff 9;; location: http://www.anc.ed.ac.uk/~stephen/emacs/
962a4216 10
6c56c80b
RS
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
962a4216
RS
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
6c56c80b 18;; GNU Emacs is distributed in the hope that it will be useful,
962a4216
RS
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26;; Boston, MA 02110-1301, USA.
962a4216 27
c6e5b93f 28;;; Commentary:
962a4216 29
c6e5b93f 30;; Installation:
19db4308
DL
31;; To get the functions in this package bound to keys, use
32;; M-x iswitchb-mode or customize the option `iswitchb-mode'.
79f0a5ed
SE
33;; Alternatively, add the following line to your .emacs:
34;; (iswitchb-mode 1)
962a4216 35
962a4216 36;; As you type in a substring, the list of buffers currently matching
19db4308 37;; the substring is displayed as you type. The list is ordered so
962a4216
RS
38;; that the most recent buffers visited come at the start of the list.
39;; The buffer at the start of the list will be the one visited when
40;; you press return. By typing more of the substring, the list is
41;; narrowed down so that gradually the buffer you want will be at the
19db4308 42;; top of the list. Alternatively, you can use C-s and C-r to rotate
962a4216
RS
43;; buffer names in the list until the one you want is at the top of
44;; the list. Completion is also available so that you can see what is
45;; common to all of the matching buffers as you type.
46
47;; This code is similar to a couple of other packages. Michael R Cook
8097dd15 48;; <cook@sightpath.com> wrote a similar buffer switching package, but
962a4216
RS
49;; does exact matching rather than substring matching on buffer names.
50;; I also modified a couple of functions from icomplete.el to provide
51;; the completion feedback in the minibuffer.
52
19db4308 53;;; Example
962a4216 54
4d8ae757
RS
55;; If I have two buffers called "123456" and "123", with "123456" the
56;; most recent, when I use iswitchb, I first of all get presented with
57;; the list of all the buffers
962a4216 58;;
19db4308 59;; iswitch {123456,123}
962a4216
RS
60;;
61;; If I then press 2:
62;; iswitch 2[3]{123456,123}
63;;
64;; The list in {} are the matching buffers, most recent first (buffers
65;; visible in the current frame are put at the end of the list by
66;; default). At any time I can select the item at the head of the
2d839509
SE
67;; list by pressing RET. I can also put the first element at the end
68;; of the list by pressing C-s, or put the last element at the head of
69;; the list by pressing C-r. The item in [] indicates what can be
70;; added to my input by pressing TAB. In this case, I will get "3"
71;; added to my input. So, press TAB:
962a4216
RS
72;; iswitch 23{123456,123}
73;;
74;; At this point, I still have two matching buffers.
75;; If I want the first buffer in the list, I simply press RET. If I
76;; wanted the second in the list, I could press C-s to move it to the
77;; top of the list and then RET to select it.
78;;
4d8ae757 79;; However, if I type 4, I only have one match left:
962a4216
RS
80;; iswitch 234[123456] [Matched]
81;;
4d8ae757
RS
82;; Since there is only one matching buffer left, it is given in [] and we
83;; see the text [Matched] afterwards. I can now press TAB or RET to go
84;; to that buffer.
962a4216
RS
85;;
86;; If however, I now type "a":
87;; iswitch 234a [No match]
88;; There are no matching buffers. If I press RET or TAB, I can be
89;; prompted to create a new buffer called "234a".
90;;
91;; Of course, where this function comes in really useful is when you
92;; can specify the buffer using only a few keystrokes. In the above
93;; example, the quickest way to get to the "123456" buffer would be
ccd2f997 94;; just to type 4 and then RET (assuming there isn't any newer buffer
962a4216
RS
95;; with 4 in its name).
96
97;; To see a full list of all matching buffers in a separate buffer,
98;; hit ? or press TAB when there are no further completions to the
ccd2f997
KH
99;; substring. Repeated TAB presses will scroll you through this
100;; separate buffer.
962a4216 101
36a3b01c
RS
102;; The buffer at the head of the list can be killed by pressing C-k.
103;; If the buffer needs saving, you will be queried before the buffer
104;; is killed.
105
106;; If you find that the file you are after is not in a buffer, you can
107;; press C-x C-f to immediately drop into find-file.
108
4d8ae757
RS
109;; See the doc string of iswitchb for full keybindings and features.
110;; (describe-function 'iswitchb)
962a4216 111
8097dd15
GM
112;; Case matching: The case of strings when matching can be ignored or
113;; used depending on the value of iswitchb-case (default is the same
114;; as case-fold-search, normally t). Imagine you have the following
19db4308 115;; buffers:
8097dd15
GM
116;;
117;; INBOX *info* *scratch*
118;;
119;; Then these will be the matching buffers, depending on how you type
120;; the two letters `in' and the value of iswitchb-case:
121;;
122;; iswitchb-case user input | matching buffers
123;; ----------------------------------------------
19db4308
DL
124;; nil in | *info*
125;; t in | INBOX, *info*
126;; t IN | INBOX
127;; t In | [No match]
8097dd15 128
962a4216
RS
129;;; Customisation
130
131;; See the User Variables section below for easy ways to change the
36a3b01c
RS
132;; functionality of the program. These are accessible using the
133;; custom package.
8ae3ef6e 134;; To modify the keybindings, use something like:
962a4216 135;;
8ae3ef6e 136;;(add-hook 'iswitchb-mode-hook 'iswitchb-my-keys)
962a4216 137;;(defun iswitchb-my-keys ()
ccd2f997 138;; "Add my keybindings for iswitchb."
8ae3ef6e 139;; (define-key iswitchb-mode-map " " 'iswitchb-next-match))
962a4216 140;;
6b0cc1b5 141;; Seeing all the matching buffers
36a3b01c 142;;
962a4216 143;; If you have many matching buffers, they may not all fit onto one
f05b502e
GM
144;; line of the minibuffer. In Emacs 21, the variable
145;; `resize-mini-windows' controls how many lines of the minibuffer can
146;; be seen. For older versions of emacs, you can use
147;; `resize-minibuffer-mode'. You can also limit iswitchb so that it
962a4216
RS
148;; only shows a certain number of lines -- see the documentation for
149;; `iswitchb-minibuffer-setup-hook'.
150
6b0cc1b5 151;; Changing the list of buffers
962a4216
RS
152
153;; By default, the list of current buffers is most recent first,
154;; oldest last, with the exception that the buffers visible in the
155;; current frame are put at the end of the list. A hook exists to
156;; allow other functions to order the list. For example, if you add:
157;;
158;; (add-hook 'iswitchb-make-buflist-hook 'iswitchb-summaries-to-end)
159;;
160;; then all buffers matching "Summary" are moved to the end of the
161;; list. (I find this handy for keeping the INBOX Summary and so on
162;; out of the way.) It also moves buffers matching "output\*$" to the
90a02640 163;; end of the list (these are created by AUCTeX when compiling.)
962a4216
RS
164;; Other functions could be made available which alter the list of
165;; matching buffers (either deleting or rearranging elements.)
166
167;; Font-Lock
168
b21688f0
EZ
169;; font-lock is used to highlight the first matching buffer. To
170;; switch this off, set (setq iswitchb-use-faces nil). Colouring of
171;; the matching buffer name was suggested by Carsten Dominik
172;; (dominik@strw.leidenuniv.nl)
962a4216 173
6b0cc1b5 174;; Replacement for read-buffer
962a4216 175
ccd2f997
KH
176;; iswitchb-read-buffer has been written to be a drop in replacement
177;; for the normal buffer selection routine `read-buffer'. To use
c6e5b93f 178;; iswitch for all buffer selections in Emacs, add:
ccd2f997 179;; (setq read-buffer-function 'iswitchb-read-buffer)
4d8ae757 180;; (This variable was introduced in Emacs 20.3.)
c6e5b93f 181;; XEmacs users can get the same behaviour by doing:
19db4308 182;; (defalias 'read-buffer 'iswitchb-read-buffer)
c6e5b93f 183;; since `read-buffer' is defined in lisp.
36a3b01c 184
4d8ae757
RS
185;; Using iswitchb for other completion tasks.
186
a2c060f6 187;; Kin Cho (kin@neoscale.com) sent the following suggestion to use
f1180544 188;; iswitchb for other completion tasks.
4d8ae757
RS
189;;
190;; (defun my-icompleting-read (prompt choices)
191;; "Use iswitch as a completing-read replacement to choose from
192;; choices. PROMPT is a string to prompt with. CHOICES is a list of
193;; strings to choose from."
194;; (let ((iswitchb-make-buflist-hook
195;; (lambda ()
196;; (setq iswitchb-temp-buflist choices))))
197;; (iswitchb-read-buffer prompt)))
198;;
199;; example:
200;; (my-icompleting-read "Which fruit? " '
201;; ("apple" "pineapple" "pear" "bananas" "oranges") )
202
a2c060f6
PJ
203;; Kin Cho also suggested the following defun. Once you have a subset of
204;; matching buffers matching your current prompt, you can then press
205;; e.g. C-o to restrict matching to those buffers and clearing the prompt:
206;; (defun iswitchb-exclude-nonmatching()
207;; "Make iswitchb work on only the currently matching names."
208;; (interactive)
209;; (setq iswitchb-buflist iswitchb-matches)
210;; (setq iswitchb-rescan t)
211;; (delete-minibuffer-contents))
212;;
213;; (add-hook 'iswitchb-define-mode-map-hook
f1180544
JB
214;; '(lambda () (define-key
215;; iswitchb-mode-map "\C-o"
a2c060f6
PJ
216;; 'iswitchb-exclude-nonmatching)))
217
4d8ae757
RS
218;; Other lisp packages extend iswitchb behaviour to other tasks. See
219;; ido.el (by Kim Storm) and mcomplete.el (Yuji Minejima).
220
221;; Window managers: Switching frames/focus follows mouse; Sawfish.
222
223;; If you switch to a buffer that is visible in another frame,
224;; iswitchb can switch focus to that frame. If your window manager
225;; uses "click to focus" policy for window selection, you should also
226;; set focus-follows-mouse to nil.
227
228;; iswitch functionality has also been implemented for switching
229;; between windows in the Sawfish window manager.
230
6b0cc1b5
SE
231;; Regexp matching
232
b21688f0
EZ
233;; There is provision for regexp matching within iswitchb, enabled
234;; through `iswitchb-regexp'. This allows you to type `c$' for
235;; example and see all buffer names ending in `c'. No completion
236;; mechanism is currently offered when regexp searching.
6b0cc1b5 237
ccd2f997 238;;; TODO
36a3b01c 239
962a4216
RS
240;;; Acknowledgements
241
242;; Thanks to Jari Aalto <jari.aalto@poboxes.com> for help with the
243;; first version of this package, iswitch-buffer. Thanks also to many
244;; others for testing earlier versions.
245
246;;; Code:
247
c6e5b93f 248;; CL needed for cadr and last
181688f2
SE
249(if (not (and (fboundp 'cadr)
250 (fboundp 'last)))
251 (require 'cl))
c6e5b93f 252
b21688f0
EZ
253(require 'font-lock)
254
36a3b01c
RS
255;; Set up the custom library.
256;; taken from http://www.dina.kvl.dk/~abraham/custom/
257(eval-and-compile
258 (condition-case ()
259 (require 'custom)
260 (error nil))
261 (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
262 nil ;; We've got what we needed
263 ;; We have the old custom-library, hack around it!
264 (defmacro defgroup (&rest args)
265 nil)
19db4308 266 (defmacro defcustom (var value doc &rest args)
b787fc05 267 `(defvar ,var ,value ,doc))))
36a3b01c 268
962a4216
RS
269;;; User Variables
270;;
271;; These are some things you might want to change.
272
36a3b01c 273(defgroup iswitchb nil
c6e5b93f 274 "Switch between buffers using substrings."
f5f727f8 275 :group 'convenience
19db4308 276 :group 'completion
36a3b01c 277 :link '(emacs-commentary-link :tag "Commentary" "iswitchb.el")
19db4308 278 :link '(url-link "http://www.anc.ed.ac.uk/~stephen/emacs/")
181688f2 279 :link '(emacs-library-link :tag "Lisp File" "iswitchb.el"))
36a3b01c
RS
280
281(defcustom iswitchb-case case-fold-search
8097dd15
GM
282 "*Non-nil if searching of buffer names should ignore case.
283If this is non-nil but the user input has any upper case letters, matching
284is temporarily case sensitive."
36a3b01c
RS
285 :type 'boolean
286 :group 'iswitchb)
962a4216 287
36a3b01c 288(defcustom iswitchb-buffer-ignore
962a4216 289 '("^ ")
6c56c80b
RS
290 "*List of regexps or functions matching buffer names to ignore.
291For example, traditional behavior is not to list buffers whose names begin
292with a space, for which the regexp is `^ '. See the source file for
36a3b01c 293example functions that filter buffernames."
e47525c4 294 :type '(repeat (choice regexp function))
36a3b01c
RS
295 :group 'iswitchb)
296
c80d9534
JW
297(defcustom iswitchb-max-to-show nil
298 "*If non-nil, limit the number of names shown in the minibuffer.
f329780b
SE
299If this value is N, and N is greater than the number of matching
300buffers, the first N/2 and the last N/2 matching buffers are
301shown. This can greatly speed up iswitchb if you have a
302multitude of buffers open."
79e1c9d4 303 :type '(choice (const :tag "Show all" nil) integer)
c80d9534
JW
304 :group 'iswitchb)
305
c4ae2d51
JW
306(defcustom iswitchb-use-virtual-buffers nil
307 "*If non-nil, refer to past buffers when none match.
308This feature relies upon the `recentf' package, which will be
309enabled if this variable is configured to a non-nil value."
310 :type 'boolean
311 :require 'recentf
312 :set (function
313 (lambda (sym value)
533b22e2 314 (if value (recentf-mode 1))
c4ae2d51
JW
315 (set sym value)))
316 :group 'iswitchb)
317
318(defvar iswitchb-virtual-buffers nil)
319
c9403808
RS
320(defcustom iswitchb-cannot-complete-hook 'iswitchb-completion-help
321 "*Hook run when `iswitchb-complete' can't complete any more.
322The most useful values are `iswitchb-completion-help', which pops up a
323window with completion alternatives, or `iswitchb-next-match' or
324`iswitchb-prev-match', which cycle the buffer list."
325 :type 'hook
326 :group 'iswitchb)
327
962a4216 328;;; Examples for setting the value of iswitchb-buffer-ignore
6b0cc1b5 329;(defun iswitchb-ignore-c-mode (name)
962a4216
RS
330; "Ignore all c mode buffers -- example function for iswitchb."
331; (save-excursion
332; (set-buffer name)
333; (string-match "^C$" mode-name)))
334
6b0cc1b5 335;(setq iswitchb-buffer-ignore '("^ " iswitchb-ignore-c-mode))
962a4216
RS
336;(setq iswitchb-buffer-ignore '("^ " "\\.c$" "\\.h$"))
337
36a3b01c 338(defcustom iswitchb-default-method 'always-frame
6c56c80b 339 "*How to switch to new buffer when using `iswitchb-buffer'.
962a4216
RS
340Possible values:
341`samewindow' Show new buffer in same window
342`otherwindow' Show new buffer in another window (same frame)
888472e0 343`display' Display buffer in another window without switching to it
962a4216
RS
344`otherframe' Show new buffer in another frame
345`maybe-frame' If a buffer is visible in another frame, prompt to ask if you
346 you want to see the buffer in the same window of the current
347 frame or in the other frame.
c6e5b93f 348`always-frame' If a buffer is visible in another frame, raise that
36a3b01c 349 frame. Otherwise, visit the buffer in the same window."
19db4308 350 :type '(choice (const samewindow)
c6e5b93f
SE
351 (const otherwindow)
352 (const display)
19db4308 353 (const otherframe)
c6e5b93f
SE
354 (const maybe-frame)
355 (const always-frame))
36a3b01c 356 :group 'iswitchb)
962a4216 357
36a3b01c 358(defcustom iswitchb-regexp nil
6c56c80b 359 "*Non-nil means that `iswitchb' will do regexp matching.
6b0cc1b5 360Value can be toggled within `iswitchb' using `iswitchb-toggle-regexp'."
36a3b01c
RS
361 :type 'boolean
362 :group 'iswitchb)
363
36a3b01c 364(defcustom iswitchb-newbuffer t
962a4216 365 "*Non-nil means create new buffer if no buffer matches substring.
36a3b01c
RS
366See also `iswitchb-prompt-newbuffer'."
367 :type 'boolean
368 :group 'iswitchb)
962a4216 369
36a3b01c 370(defcustom iswitchb-prompt-newbuffer t
962a4216 371 "*Non-nil means prompt user to confirm before creating new buffer.
36a3b01c
RS
372See also `iswitchb-newbuffer'."
373 :type 'boolean
374 :group 'iswitchb)
375
b21688f0 376(defcustom iswitchb-use-faces t
6b0cc1b5 377 "*Non-nil means use font-lock fonts for showing first match."
36a3b01c
RS
378 :type 'boolean
379 :group 'iswitchb)
b21688f0 380(define-obsolete-variable-alias 'iswitchb-use-fonts 'iswitchb-use-faces "22.1")
962a4216 381
f5bd1691
GM
382(defcustom iswitchb-use-frame-buffer-list nil
383 "*Non-nil means use the currently selected frame's buffer list."
384 :type 'boolean
385 :group 'iswitchb)
386
36a3b01c 387(defcustom iswitchb-make-buflist-hook nil
19db4308 388 "Hook to run when list of matching buffers is created."
36a3b01c
RS
389 :type 'hook
390 :group 'iswitchb)
391
962a4216
RS
392(defvar iswitchb-all-frames 'visible
393 "*Argument to pass to `walk-windows' when finding visible buffers.
394See documentation of `walk-windows' for useful values.")
395
6b0cc1b5 396(defcustom iswitchb-minibuffer-setup-hook nil
19db4308 397 "Iswitchb-specific customization of minibuffer setup.
962a4216 398
6c56c80b 399This hook is run during minibuffer setup iff `iswitchb' will be active.
33a316ba
SE
400For instance:
401\(add-hook 'iswitchb-minibuffer-setup-hook
402 '\(lambda () (set (make-local-variable 'max-mini-window-height) 3)))
403will constrain the minibuffer to a maximum height of 3 lines when
404iswitchb is running."
6b0cc1b5
SE
405 :type 'hook
406 :group 'iswitchb)
407
54907cdc 408(defface iswitchb-single-match
b21688f0
EZ
409 '((t
410 (:inherit font-lock-comment-face)))
411 "Iswitchb face for single matching buffer name."
412 :version "22.1"
413 :group 'iswitchb)
414
54907cdc 415(defface iswitchb-current-match
b21688f0
EZ
416 '((t
417 (:inherit font-lock-function-name-face)))
418 "Iswitchb face for current matching buffer name."
419 :version "22.1"
420 :group 'iswitchb)
421
54907cdc 422(defface iswitchb-virtual-matches
b21688f0
EZ
423 '((t
424 (:inherit font-lock-builtin-face)))
425 "Iswitchb face for matching virtual buffer names.
426See also `iswitchb-use-virtual-buffers'."
427 :version "22.1"
428 :group 'iswitchb)
429
54907cdc 430(defface iswitchb-invalid-regexp
b21688f0
EZ
431 '((t
432 (:inherit font-lock-warning-face)))
433 "Iswitchb face for indicating invalid regexp. "
434 :version "22.1"
435 :group 'iswitchb)
436
6b0cc1b5
SE
437;; Do we need the variable iswitchb-use-mycompletion?
438
6b0cc1b5
SE
439;;; Internal Variables
440
441(defvar iswitchb-method nil
19db4308 442 "Stores the method for viewing the selected buffer.
6b0cc1b5
SE
443Its value is one of `samewindow', `otherwindow', `display', `otherframe',
444`maybe-frame' or `always-frame'. See `iswitchb-default-method' for
445details of values.")
962a4216
RS
446
447(defvar iswitchb-eoinput 1
448 "Point where minibuffer input ends and completion info begins.
6c56c80b 449Copied from `icomplete-eoinput'.")
962a4216
RS
450(make-variable-buffer-local 'iswitchb-eoinput)
451
962a4216
RS
452(defvar iswitchb-buflist nil
453 "Stores the current list of buffers that will be searched through.
454The list is ordered, so that the most recent buffers come first,
455although by default, the buffers visible in the current frame are put
456at the end of the list. Created by `iswitchb-make-buflist'.")
457
458;; todo -- is this necessary?
459
460(defvar iswitchb-use-mycompletion nil
19db4308 461 "Non-nil means use `iswitchb-buffer' completion feedback.
6c56c80b
RS
462Should only be set to t by iswitchb functions, so that it doesn't
463interfere with other minibuffer usage.")
962a4216 464
19db4308 465(defvar iswitchb-change-word-sub nil
962a4216
RS
466 "Private variable used by `iswitchb-word-matching-substring'.")
467
962a4216
RS
468(defvar iswitchb-common-match-string nil
469 "Stores the string that is common to all matching buffers.")
470
962a4216
RS
471(defvar iswitchb-rescan nil
472 "Non-nil means we need to regenerate the list of matching buffers.")
473
474(defvar iswitchb-text nil
475 "Stores the users string as it is typed in.")
476
477(defvar iswitchb-matches nil
ccd2f997 478 "List of buffers currently matching `iswitchb-text'.")
962a4216 479
19db4308
DL
480(defvar iswitchb-mode-map
481 (let ((map (make-sparse-keymap)))
482 (set-keymap-parent map minibuffer-local-map)
483 (define-key map "?" 'iswitchb-completion-help)
484 (define-key map "\C-s" 'iswitchb-next-match)
485 (define-key map "\C-r" 'iswitchb-prev-match)
486 (define-key map "\t" 'iswitchb-complete)
487 (define-key map "\C-j" 'iswitchb-select-buffer-text)
488 (define-key map "\C-t" 'iswitchb-toggle-regexp)
489 (define-key map "\C-x\C-f" 'iswitchb-find-file)
490 (define-key map "\C-c" 'iswitchb-toggle-case)
491 (define-key map "\C-k" 'iswitchb-kill-buffer)
492 (define-key map "\C-m" 'iswitchb-exit-minibuffer)
493 map)
494 "Minibuffer keymap for `iswitchb-buffer'.")
495
496(defvar iswitchb-global-map
497 (let ((map (make-sparse-keymap)))
498 (substitute-key-definition 'switch-to-buffer ; normally C-x b
499 'iswitchb-buffer map global-map)
500 (substitute-key-definition 'switch-to-buffer-other-window ; C-x 4 b
501 'iswitchb-buffer-other-window map global-map)
502 (substitute-key-definition 'switch-to-buffer-other-frame ; C-x 5 b
503 'iswitchb-buffer-other-frame map global-map)
504 (substitute-key-definition 'display-buffer ; C-x 4 C-o
505 'iswitchb-display-buffer map global-map)
506 map)
971cb834 507 "Global keymap for `iswitchb-mode'.")
19db4308
DL
508
509(defvar iswitchb-history nil
6c56c80b 510 "History of buffers selected using `iswitchb-buffer'.")
962a4216 511
19db4308
DL
512(defvar iswitchb-exit nil
513 "Flag to monitor how `iswitchb-buffer' exits.
6c56c80b
RS
514If equal to `takeprompt', we use the prompt as the buffer name to be
515selected.")
962a4216
RS
516
517(defvar iswitchb-buffer-ignore-orig nil
518 "Stores original value of `iswitchb-buffer-ignore'.")
519
6b0cc1b5
SE
520(defvar iswitchb-default nil
521 "Default buffer for iswitchb.")
962a4216 522
02e526ad
SE
523;; The following variables are needed to keep the byte compiler quiet.
524(defvar iswitchb-require-match nil
525 "Non-nil if matching buffer must be selected.")
526
527(defvar iswitchb-temp-buflist nil
528 "Stores a temporary version of the buffer list being created.")
529
530(defvar iswitchb-bufs-in-frame nil
531 "List of the buffers visible in the current frame.")
532
c7b89861
EZ
533(defvar iswitchb-minibuf-depth nil
534 "Value we expect to be returned by `minibuffer-depth' in the minibuffer.")
535
b21688f0
EZ
536(defvar iswitchb-common-match-inserted nil
537 "Non-nil if we have just inserted a common match in the minibuffer.")
538
539(defvar iswitchb-invalid-regexp)
540
962a4216
RS
541;;; FUNCTIONS
542
19db4308 543;;; ISWITCHB KEYMAP
962a4216 544(defun iswitchb-define-mode-map ()
19db4308
DL
545 "Set up the keymap for `iswitchb-buffer'.
546This is obsolete. Use \\[iswitchb-mode] or customize the
547variable `iswitchb-mode'."
962a4216
RS
548 (interactive)
549 (let (map)
ccd2f997 550 ;; generated every time so that it can inherit new functions.
962a4216
RS
551 ;;(or iswitchb-mode-map
552
553 (setq map (copy-keymap minibuffer-local-map))
554 (define-key map "?" 'iswitchb-completion-help)
555 (define-key map "\C-s" 'iswitchb-next-match)
556 (define-key map "\C-r" 'iswitchb-prev-match)
557 (define-key map "\t" 'iswitchb-complete)
558 (define-key map "\C-j" 'iswitchb-select-buffer-text)
559 (define-key map "\C-t" 'iswitchb-toggle-regexp)
36a3b01c 560 (define-key map "\C-x\C-f" 'iswitchb-find-file)
962a4216
RS
561 ;;(define-key map "\C-a" 'iswitchb-toggle-ignore)
562 (define-key map "\C-c" 'iswitchb-toggle-case)
36a3b01c 563 (define-key map "\C-k" 'iswitchb-kill-buffer)
ccd2f997 564 (define-key map "\C-m" 'iswitchb-exit-minibuffer)
962a4216 565 (setq iswitchb-mode-map map)
181688f2 566 (run-hooks 'iswitchb-define-mode-map-hook)))
f1180544 567
962a4216
RS
568;;; MAIN FUNCTION
569(defun iswitchb ()
570 "Switch to buffer matching a substring.
571As you type in a string, all of the buffers matching the string are
572displayed. When you have found the buffer you want, it can then be
573selected. As you type, most keys have their normal keybindings,
574except for the following:
575\\<iswitchb-mode-map>
576
577RET Select the buffer at the front of the list of matches. If the
6c56c80b 578list is empty, possibly prompt to create new buffer.
962a4216
RS
579
580\\[iswitchb-select-buffer-text] Select the current prompt as the buffer.
581If no buffer is found, prompt for a new one.
582
583\\[iswitchb-next-match] Put the first element at the end of the list.
584\\[iswitchb-prev-match] Put the last element at the start of the list.
19db4308 585\\[iswitchb-complete] Complete a common suffix to the current string that
962a4216
RS
586matches all buffers. If there is only one match, select that buffer.
587If there is no common suffix, show a list of all matching buffers
588in a separate window.
ccd2f997 589\\[iswitchb-toggle-regexp] Toggle regexp searching.
962a4216 590\\[iswitchb-toggle-case] Toggle case-sensitive searching of buffer names.
36a3b01c 591\\[iswitchb-completion-help] Show list of matching buffers in separate window.
19db4308 592\\[iswitchb-find-file] Exit iswitchb and drop into `find-file'.
36a3b01c 593\\[iswitchb-kill-buffer] Kill buffer at head of buffer list."
962a4216
RS
594 ;;\\[iswitchb-toggle-ignore] Toggle ignoring certain buffers (see \
595 ;;`iswitchb-buffer-ignore')
f1180544 596
8ae3ef6e 597 (let* ((prompt "iswitch ")
b21688f0 598 iswitchb-invalid-regexp
8ae3ef6e 599 (buf (iswitchb-read-buffer prompt)))
ccd2f997 600
ccd2f997
KH
601 ;;(message "chosen text %s" iswitchb-final-text)
602 ;; Choose the buffer name: either the text typed in, or the head
603 ;; of the list of matches
604
605 (cond ( (eq iswitchb-exit 'findfile)
606 (call-interactively 'find-file))
b21688f0
EZ
607 (iswitchb-invalid-regexp
608 (message "Won't make invalid regexp named buffer"))
ccd2f997
KH
609 (t
610 ;; View the buffer
c6e5b93f 611 ;;(message "go to buf %s" buf)
ccd2f997
KH
612 ;; Check buf is non-nil.
613 (if buf
614 (if (get-buffer buf)
615 ;; buffer exists, so view it and then exit
616 (iswitchb-visit-buffer buf)
617 ;; else buffer doesn't exist
618 (iswitchb-possible-new-buffer buf)))
181688f2 619 ))))
ccd2f997 620
c4ae2d51
JW
621(defun iswitchb-read-buffer (prompt &optional default require-match
622 start matches-set)
ccd2f997 623 "Replacement for the built-in `read-buffer'.
19db4308 624Return the name of a buffer selected.
c4ae2d51
JW
625PROMPT is the prompt to give to the user.
626DEFAULT if given is the default buffer to be selected, which will
627go to the front of the list.
628If REQUIRE-MATCH is non-nil, an existing-buffer must be selected.
629If START is a string, the selection process is started with that
630string.
631If MATCHES-SET is non-nil, the buflist is not updated before
632the selection process begins. Used by isearchb.el."
962a4216
RS
633 (let
634 (
962a4216
RS
635 buf-sel
636 iswitchb-final-text
962a4216 637 (icomplete-mode nil) ;; prevent icomplete starting up
b21688f0 638 )
ccd2f997 639
962a4216 640 (iswitchb-define-mode-map)
962a4216 641 (setq iswitchb-exit nil)
6b0cc1b5
SE
642 (setq iswitchb-default
643 (if (bufferp default)
644 (buffer-name default)
645 default))
c4ae2d51
JW
646 (setq iswitchb-text (or start ""))
647 (unless matches-set
648 (setq iswitchb-rescan t)
649 (iswitchb-make-buflist iswitchb-default)
650 (iswitchb-set-matches))
19db4308 651 (let
ccd2f997 652 ((minibuffer-local-completion-map iswitchb-mode-map)
c7b89861
EZ
653 ;; Record the minibuffer depth that we expect to find once
654 ;; the minibuffer is set up and iswitchb-entryfn-p is called.
655 (iswitchb-minibuf-depth (1+ (minibuffer-depth)))
181688f2 656 (iswitchb-require-match require-match))
36a3b01c 657 ;; prompt the user for the buffer name
19db4308 658 (setq iswitchb-final-text (completing-read
c4ae2d51 659 prompt ;the prompt
660e161f 660 '(("dummy" . 1)) ;table
c4ae2d51
JW
661 nil ;predicate
662 nil ;require-match [handled elsewhere]
663 start ;initial-contents
ccd2f997 664 'iswitchb-history)))
4dddd07f
SE
665 (if (and (not (eq iswitchb-exit 'usefirst))
666 (get-buffer iswitchb-final-text))
8ae3ef6e 667 ;; This happens for example if the buffer was chosen with the mouse.
c4ae2d51
JW
668 (setq iswitchb-matches (list iswitchb-final-text)
669 iswitchb-virtual-buffers nil))
670
671 ;; If no buffer matched, but a virtual buffer was selected, visit
672 ;; that file now and act as though that buffer had been selected.
673 (if (and iswitchb-virtual-buffers
674 (not (iswitchb-existing-buffer-p)))
675 (let ((virt (car iswitchb-virtual-buffers)))
676 (find-file-noselect (cdr virt))
677 (setq iswitchb-matches (list (car virt))
678 iswitchb-virtual-buffers nil)))
8ae3ef6e 679
ccd2f997 680 ;; Handling the require-match must be done in a better way.
c4ae2d51
JW
681 (if (and require-match
682 (not (iswitchb-existing-buffer-p)))
19db4308 683 (error "Must specify valid buffer"))
ccd2f997 684
c4ae2d51
JW
685 (if (or (eq iswitchb-exit 'takeprompt)
686 (null iswitchb-matches))
ccd2f997
KH
687 (setq buf-sel iswitchb-final-text)
688 ;; else take head of list
689 (setq buf-sel (car iswitchb-matches)))
f1180544 690
ccd2f997 691 ;; Or possibly choose the default buffer
19db4308 692 (if (equal iswitchb-final-text "")
c4ae2d51 693 (setq buf-sel (car iswitchb-matches)))
36a3b01c 694
ccd2f997 695 buf-sel))
36a3b01c 696
ccd2f997
KH
697(defun iswitchb-existing-buffer-p ()
698 "Return non-nil if there is a matching buffer."
699 (not (null iswitchb-matches)))
962a4216
RS
700
701;;; COMPLETION CODE
702
703(defun iswitchb-set-common-completion ()
6c56c80b
RS
704 "Find common completion of `iswitchb-text' in `iswitchb-matches'.
705The result is stored in `iswitchb-common-match-string'."
962a4216
RS
706
707 (let* (val)
708 (setq iswitchb-common-match-string nil)
709 (if (and iswitchb-matches
6b0cc1b5 710 (not iswitchb-regexp) ;; testing
962a4216
RS
711 (stringp iswitchb-text)
712 (> (length iswitchb-text) 0))
713 (if (setq val (iswitchb-find-common-substring
714 iswitchb-matches iswitchb-text))
715 (setq iswitchb-common-match-string val)))
181688f2 716 val))
962a4216
RS
717
718(defun iswitchb-complete ()
719 "Try and complete the current pattern amongst the buffer names."
720 (interactive)
721 (let (res)
722 (cond ((not iswitchb-matches)
c9403808 723 (run-hooks 'iswitchb-cannot-complete-hook))
b21688f0
EZ
724 (iswitchb-invalid-regexp
725 ;; Do nothing
726 )
ccd2f997 727 ((= 1 (length iswitchb-matches))
962a4216
RS
728 ;; only one choice, so select it.
729 (exit-minibuffer))
f1180544 730
962a4216
RS
731 (t
732 ;; else there could be some completions
6b0cc1b5 733 (setq res iswitchb-common-match-string)
962a4216 734 (if (and (not (memq res '(t nil)))
36a3b01c 735 (not (equal res iswitchb-text)))
ccd2f997 736 ;; found something to complete, so put it in the minibuffer.
962a4216 737 (progn
b21688f0
EZ
738 (setq iswitchb-rescan nil
739 iswitchb-common-match-inserted t)
53811b42 740 (delete-region (minibuffer-prompt-end) (point))
962a4216
RS
741 (insert res))
742 ;; else nothing to complete
c9403808 743 (run-hooks 'iswitchb-cannot-complete-hook)
181688f2 744 )))))
962a4216
RS
745
746;;; TOGGLE FUNCTIONS
747
748(defun iswitchb-toggle-case ()
19db4308 749 "Toggle the value of variable `iswitchb-case'."
962a4216
RS
750 (interactive)
751 (setq iswitchb-case (not iswitchb-case))
752 ;; ask for list to be regenerated.
181688f2 753 (setq iswitchb-rescan t))
962a4216
RS
754
755(defun iswitchb-toggle-regexp ()
756 "Toggle the value of `iswitchb-regexp'."
757 (interactive)
758 (setq iswitchb-regexp (not iswitchb-regexp))
759 ;; ask for list to be regenerated.
181688f2 760 (setq iswitchb-rescan t))
962a4216
RS
761
762(defun iswitchb-toggle-ignore ()
763 "Toggle ignoring buffers specified with `iswitchb-buffer-ignore'."
764 (interactive)
765 (if iswitchb-buffer-ignore
766 (progn
767 (setq iswitchb-buffer-ignore-orig iswitchb-buffer-ignore)
181688f2 768 (setq iswitchb-buffer-ignore nil))
962a4216 769 ;; else
181688f2 770 (setq iswitchb-buffer-ignore iswitchb-buffer-ignore-orig))
6b0cc1b5 771 (iswitchb-make-buflist iswitchb-default)
962a4216 772 ;; ask for list to be regenerated.
181688f2 773 (setq iswitchb-rescan t))
962a4216 774
ccd2f997
KH
775(defun iswitchb-exit-minibuffer ()
776 "Exit minibuffer, but make sure we have a match if one is needed."
777 (interactive)
778 (if (or (not iswitchb-require-match)
779 (iswitchb-existing-buffer-p))
4dddd07f
SE
780 (progn
781 (setq iswitchb-exit 'usefirst)
782 (throw 'exit nil))))
962a4216
RS
783
784(defun iswitchb-select-buffer-text ()
6c56c80b
RS
785 "Select the buffer named by the prompt.
786If no buffer exactly matching the prompt exists, maybe create a new one."
962a4216
RS
787 (interactive)
788 (setq iswitchb-exit 'takeprompt)
789 (exit-minibuffer))
790
36a3b01c 791(defun iswitchb-find-file ()
19db4308 792 "Drop into `find-file' from buffer switching."
36a3b01c
RS
793 (interactive)
794 (setq iswitchb-exit 'findfile)
795 (exit-minibuffer))
796
c4ae2d51
JW
797(eval-when-compile
798 (defvar recentf-list))
799
19db4308 800(defun iswitchb-next-match ()
962a4216
RS
801 "Put first element of `iswitchb-matches' at the end of the list."
802 (interactive)
36a3b01c 803 (let ((next (cadr iswitchb-matches)))
c4ae2d51
JW
804 (if (and (null next) iswitchb-virtual-buffers)
805 (setq recentf-list
806 (iswitchb-chop recentf-list
807 (cdr (cadr iswitchb-virtual-buffers))))
808 (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist next)))
181688f2 809 (setq iswitchb-rescan t)))
962a4216 810
19db4308 811(defun iswitchb-prev-match ()
962a4216
RS
812 "Put last element of `iswitchb-matches' at the front of the list."
813 (interactive)
36a3b01c 814 (let ((prev (car (last iswitchb-matches))))
c4ae2d51
JW
815 (if (and (null prev) iswitchb-virtual-buffers)
816 (setq recentf-list
817 (iswitchb-chop recentf-list
818 (cdr (car (last iswitchb-virtual-buffers)))))
819 (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist prev)))
181688f2 820 (setq iswitchb-rescan t)))
36a3b01c
RS
821
822(defun iswitchb-chop (list elem)
823 "Remove all elements before ELEM and put them at the end of LIST."
824 (let ((ret nil)
825 (next nil)
826 (sofar nil))
827 (while (not ret)
828 (setq next (car list))
829 (if (equal next elem)
830 (setq ret (append list (nreverse sofar)))
831 ;; else
832 (progn
833 (setq list (cdr list))
834 (setq sofar (cons next sofar)))))
835 ret))
962a4216 836
962a4216
RS
837;;; CREATE LIST OF ALL CURRENT BUFFERS
838
ccd2f997 839(defun iswitchb-make-buflist (default)
6c56c80b 840 "Set `iswitchb-buflist' to the current list of buffers.
36a3b01c 841Currently visible buffers are put at the end of the list.
19db4308 842The hook `iswitchb-make-buflist-hook' is run after the list has been
36a3b01c 843created to allow the user to further modify the order of the buffer names
ccd2f997
KH
844in this list. If DEFAULT is non-nil, and corresponds to an existing buffer,
845it is put to the start of the list."
19db4308 846 (setq iswitchb-buflist
36a3b01c 847 (let* ((iswitchb-current-buffers (iswitchb-get-buffers-in-frames))
ceba0dac
GM
848 (iswitchb-temp-buflist
849 (delq nil
850 (mapcar
851 (lambda (x)
852 (let ((b-name (buffer-name x)))
853 (if (not
854 (or
855 (iswitchb-ignore-buffername-p b-name)
856 (memq b-name iswitchb-current-buffers)))
857 b-name)))
858 (buffer-list (and iswitchb-use-frame-buffer-list
859 (selected-frame)))))))
860 (setq iswitchb-temp-buflist
861 (nconc iswitchb-temp-buflist iswitchb-current-buffers))
962a4216 862 (run-hooks 'iswitchb-make-buflist-hook)
ceba0dac 863 ;; Should this be after the hooks, or should the hooks be the
ccd2f997
KH
864 ;; final thing to be run?
865 (if default
866 (progn
19db4308 867 (setq iswitchb-temp-buflist
02e526ad 868 (delete default iswitchb-temp-buflist))
19db4308 869 (setq iswitchb-temp-buflist
02e526ad
SE
870 (cons default iswitchb-temp-buflist))))
871 iswitchb-temp-buflist)))
962a4216 872
36a3b01c 873(defun iswitchb-to-end (lst)
02e526ad 874 "Move the elements from LST to the end of `iswitchb-temp-buflist'."
561ec225
SM
875 (dolist (elem lst)
876 (setq iswitchb-temp-buflist (delq elem iswitchb-temp-buflist)))
ceba0dac 877 (setq iswitchb-temp-buflist (nconc iswitchb-temp-buflist lst)))
962a4216 878
962a4216 879(defun iswitchb-get-buffers-in-frames (&optional current)
962a4216 880 "Return the list of buffers that are visible in the current frame.
19db4308 881If optional argument CURRENT is given, restrict searching to the
962a4216
RS
882current frame, rather than all frames, regardless of value of
883`iswitchb-all-frames'."
962a4216 884 (let ((iswitchb-bufs-in-frame nil))
962a4216 885 (walk-windows 'iswitchb-get-bufname nil
19db4308 886 (if current
962a4216
RS
887 nil
888 iswitchb-all-frames))
889 iswitchb-bufs-in-frame))
890
962a4216
RS
891(defun iswitchb-get-bufname (win)
892 "Used by `iswitchb-get-buffers-in-frames' to walk through all windows."
ae5ac7d0
RS
893 (let ((buf (buffer-name (window-buffer win))))
894 (if (not (member buf iswitchb-bufs-in-frame))
895 ;; Only add buf if it is not already in list.
896 ;; This prevents same buf in two different windows being
897 ;; put into the list twice.
898 (setq iswitchb-bufs-in-frame
899 (cons buf iswitchb-bufs-in-frame)))))
962a4216 900
962a4216
RS
901;;; FIND MATCHING BUFFERS
902
903(defun iswitchb-set-matches ()
904 "Set `iswitchb-matches' to the list of buffers matching prompt."
962a4216
RS
905 (if iswitchb-rescan
906 (setq iswitchb-matches
181688f2 907 (let* ((buflist iswitchb-buflist))
36a3b01c 908 (iswitchb-get-matched-buffers iswitchb-text iswitchb-regexp
c4ae2d51
JW
909 buflist))
910 iswitchb-virtual-buffers nil)))
36a3b01c
RS
911
912(defun iswitchb-get-matched-buffers (regexp
913 &optional string-format buffer-list)
6b0cc1b5
SE
914 "Return buffers matching REGEXP.
915If STRING-FORMAT is nil, consider REGEXP as just a string.
6c56c80b 916BUFFER-LIST can be list of buffers or list of strings."
561ec225
SM
917 (let* ((case-fold-search (iswitchb-case))
918 name ret)
919 (if (null string-format) (setq regexp (regexp-quote regexp)))
b21688f0 920 (setq iswitchb-invalid-regexp nil)
561ec225
SM
921 (condition-case error
922 (dolist (x buffer-list (nreverse ret))
923 (setq name (if (stringp x) x (buffer-name x)))
924 (when (and (string-match regexp name)
925 (not (iswitchb-ignore-buffername-p name)))
926 (push name ret)))
927 (invalid-regexp
928 (setq iswitchb-invalid-regexp t)
929 (cdr error)))))
962a4216
RS
930
931(defun iswitchb-ignore-buffername-p (bufname)
932 "Return t if the buffer BUFNAME should be ignored."
933 (let ((data (match-data))
934 (re-list iswitchb-buffer-ignore)
935 ignorep
181688f2 936 nextstr)
962a4216
RS
937 (while re-list
938 (setq nextstr (car re-list))
939 (cond
940 ((stringp nextstr)
941 (if (string-match nextstr bufname)
942 (progn
943 (setq ignorep t)
944 (setq re-list nil))))
945 ((fboundp nextstr)
946 (if (funcall nextstr bufname)
947 (progn
948 (setq ignorep t)
181688f2 949 (setq re-list nil)))))
962a4216 950 (setq re-list (cdr re-list)))
25c80f5c 951 (set-match-data data)
962a4216
RS
952
953 ;; return the result
181688f2 954 ignorep))
962a4216 955
962a4216
RS
956(defun iswitchb-word-matching-substring (word)
957 "Return part of WORD before 1st match to `iswitchb-change-word-sub'.
958If `iswitchb-change-word-sub' cannot be found in WORD, return nil."
8097dd15 959 (let ((case-fold-search (iswitchb-case)))
962a4216
RS
960 (let ((m (string-match iswitchb-change-word-sub word)))
961 (if m
962 (substring word m)
963 ;; else no match
964 nil))))
965
962a4216
RS
966(defun iswitchb-find-common-substring (lis subs)
967 "Return common string following SUBS in each element of LIS."
968 (let (res
969 alist
181688f2 970 iswitchb-change-word-sub)
962a4216
RS
971 (setq iswitchb-change-word-sub
972 (if iswitchb-regexp
973 subs
974 (regexp-quote subs)))
975 (setq res (mapcar 'iswitchb-word-matching-substring lis))
ccd2f997 976 (setq res (delq nil res)) ;; remove any nil elements (shouldn't happen)
962a4216
RS
977 (setq alist (mapcar 'iswitchb-makealist res)) ;; could use an OBARRAY
978
979 ;; try-completion returns t if there is an exact match.
8097dd15 980 (let ((completion-ignore-case (iswitchb-case)))
962a4216 981
181688f2 982 (try-completion subs alist))))
962a4216
RS
983
984(defun iswitchb-makealist (res)
985 "Return dotted pair (RES . 1)."
986 (cons res 1))
987
988;; from Wayne Mesard <wmesard@esd.sgi.com>
989(defun iswitchb-rotate-list (lis)
19db4308 990 "Destructively remove the last element from LIS.
962a4216
RS
991Return the modified list with the last element prepended to it."
992 (if (<= (length lis) 1)
993 lis
994 (let ((las lis)
995 (prev lis))
996 (while (consp (cdr las))
997 (setq prev las
998 las (cdr las)))
999 (setcdr prev nil)
181688f2 1000 (cons (car las) lis))))
962a4216
RS
1001
1002(defun iswitchb-completion-help ()
8ae3ef6e 1003 "Show possible completions in a *Completions* buffer."
962a4216 1004 ;; we could allow this buffer to be used to select match, but I think
36a3b01c 1005 ;; choose-completion-string will need redefining, so it just inserts
19db4308 1006 ;; choice with out any previous input.
962a4216 1007 (interactive)
36a3b01c 1008 (setq iswitchb-rescan nil)
8ae3ef6e
SM
1009 (let ((buf (current-buffer))
1010 (temp-buf "*Completions*")
1011 (win))
ccd2f997 1012
b21688f0
EZ
1013 (if (and (eq last-command this-command)
1014 (not iswitchb-common-match-inserted))
ccd2f997
KH
1015 ;; scroll buffer
1016 (progn
1017 (set-buffer temp-buf)
1018 (setq win (get-buffer-window temp-buf))
1019 (if (pos-visible-in-window-p (point-max) win)
1020 (set-window-start win (point-min))
1021 (scroll-other-window))
181688f2 1022 (set-buffer buf))
f1180544 1023
ccd2f997 1024 (with-output-to-temp-buffer temp-buf
2d839509 1025 (if (featurep 'xemacs)
f1180544 1026
ccd2f997
KH
1027 ;; XEmacs extents are put on by default, doesn't seem to be
1028 ;; any way of switching them off.
1029 (display-completion-list (if iswitchb-matches
1030 iswitchb-matches
1031 iswitchb-buflist)
1032 :help-string "iswitchb "
19db4308
DL
1033 :activate-callback
1034 (lambda (x y z)
1035 (message "doesn't work yet, sorry!")))
ccd2f997 1036 ;; else running Emacs
19db4308
DL
1037 (with-current-buffer standard-output
1038 (fundamental-mode))
ccd2f997 1039 (display-completion-list (if iswitchb-matches
19db4308 1040 iswitchb-matches
b21688f0
EZ
1041 iswitchb-buflist))))
1042 (setq iswitchb-common-match-inserted nil))))
ccd2f997 1043
36a3b01c
RS
1044;;; KILL CURRENT BUFFER
1045
1046(defun iswitchb-kill-buffer ()
ccd2f997 1047 "Kill the buffer at the head of `iswitchb-matches'."
36a3b01c
RS
1048 (interactive)
1049 (let ( (enable-recursive-minibuffers t)
1050 buf)
1051
1052 (setq buf (car iswitchb-matches))
1053 ;; check to see if buf is non-nil.
1054 (if buf
1055 (progn
1056 (kill-buffer buf)
1057
1058 ;; Check if buffer exists. XEmacs gnuserv.el makes alias
1059 ;; for kill-buffer which does not return t if buffer is
1060 ;; killed, so we can't rely on kill-buffer return value.
1061 (if (get-buffer buf)
1062 ;; buffer couldn't be killed.
19db4308 1063 (setq iswitchb-rescan t)
36a3b01c
RS
1064 ;; else buffer was killed so remove name from list.
1065 (setq iswitchb-buflist (delq buf iswitchb-buflist)))))))
1066
962a4216
RS
1067;;; VISIT CHOSEN BUFFER
1068(defun iswitchb-visit-buffer (buffer)
1069 "Visit buffer named BUFFER according to `iswitchb-method'."
1070 (let* (win newframe)
1071 (cond
1072 ((eq iswitchb-method 'samewindow)
1073 (switch-to-buffer buffer))
1074
1075 ((memq iswitchb-method '(always-frame maybe-frame))
1076 (cond
1077 ((and (setq win (iswitchb-window-buffer-p buffer))
1078 (or (eq iswitchb-method 'always-frame)
1079 (y-or-n-p "Jump to frame? ")))
1080 (setq newframe (window-frame win))
2d839509 1081 (if (fboundp 'select-frame-set-input-focus)
4d8ae757
RS
1082 (select-frame-set-input-focus newframe)
1083 (raise-frame newframe)
1084 (select-frame newframe)
1085 )
1086 (select-window win))
962a4216
RS
1087 (t
1088 ;; No buffer in other frames...
1089 (switch-to-buffer buffer)
1090 )))
1091
962a4216
RS
1092 ((eq iswitchb-method 'otherwindow)
1093 (switch-to-buffer-other-window buffer))
1094
888472e0
RS
1095 ((eq iswitchb-method 'display)
1096 (display-buffer buffer))
1097
962a4216
RS
1098 ((eq iswitchb-method 'otherframe)
1099 (progn
1100 (switch-to-buffer-other-frame buffer)
2d839509 1101 (if (fboundp 'select-frame-set-input-focus)
4d8ae757 1102 (select-frame-set-input-focus (selected-frame)))
181688f2 1103 )))))
962a4216
RS
1104
1105(defun iswitchb-possible-new-buffer (buf)
1106 "Possibly create and visit a new buffer called BUF."
1107
1108 (let ((newbufcreated))
1109 (if (and iswitchb-newbuffer
1110 (or
1111 (not iswitchb-prompt-newbuffer)
f1180544 1112
962a4216
RS
1113 (and iswitchb-prompt-newbuffer
1114 (y-or-n-p
1115 (format
1116 "No buffer matching `%s', create one? "
1117 buf)))))
1118 ;; then create a new buffer
1119 (progn
1120 (setq newbufcreated (get-buffer-create buf))
1121 (if (fboundp 'set-buffer-major-mode)
1122 (set-buffer-major-mode newbufcreated))
1123 (iswitchb-visit-buffer newbufcreated))
1124 ;; else wont create new buffer
181688f2 1125 (message (format "no buffer matching `%s'" buf)))))
962a4216
RS
1126
1127(defun iswitchb-window-buffer-p (buffer)
6c56c80b
RS
1128 "Return window pointer if BUFFER is visible in another frame.
1129If BUFFER is visible in the current frame, return nil."
962a4216 1130 (interactive)
962a4216
RS
1131 (let ((blist (iswitchb-get-buffers-in-frames 'current)))
1132 ;;If the buffer is visible in current frame, return nil
1133 (if (memq buffer blist)
1134 nil
ccd2f997
KH
1135 ;; maybe in other frame or icon
1136 (get-buffer-window buffer 0) ; better than 'visible
962a4216
RS
1137 )))
1138
962a4216 1139(defun iswitchb-default-keybindings ()
6c56c80b 1140 "Set up default keybindings for `iswitchb-buffer'.
ee5897a4 1141Call this function to override the normal bindings. This function also
19db4308
DL
1142adds a hook to the minibuffer.
1143
1144Obsolescent. Use `iswitchb-mode'."
962a4216 1145 (interactive)
ee5897a4 1146 (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)
322524b2
SE
1147 (global-set-key "\C-xb" 'iswitchb-buffer)
1148 (global-set-key "\C-x4b" 'iswitchb-buffer-other-window)
1149 (global-set-key "\C-x4\C-o" 'iswitchb-display-buffer)
1150 (global-set-key "\C-x5b" 'iswitchb-buffer-other-frame))
962a4216 1151
962a4216
RS
1152(defun iswitchb-buffer ()
1153 "Switch to another buffer.
1154
1155The buffer name is selected interactively by typing a substring. The
1156buffer is displayed according to `iswitchb-default-method' -- the
1157default is to show it in the same window, unless it is already visible
6c56c80b
RS
1158in another frame.
1159For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1160 (interactive)
1161 (setq iswitchb-method iswitchb-default-method)
ccd2f997 1162 (iswitchb))
962a4216 1163
962a4216
RS
1164(defun iswitchb-buffer-other-window ()
1165 "Switch to another buffer and show it in another window.
1166The buffer name is selected interactively by typing a substring.
6c56c80b 1167For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1168 (interactive)
1169 (setq iswitchb-method 'otherwindow)
ccd2f997 1170 (iswitchb))
962a4216 1171
888472e0
RS
1172(defun iswitchb-display-buffer ()
1173 "Display a buffer in another window but don't select it.
1174The buffer name is selected interactively by typing a substring.
1175For details of keybindings, do `\\[describe-function] iswitchb'."
1176 (interactive)
1177 (setq iswitchb-method 'display)
ccd2f997 1178 (iswitchb))
888472e0 1179
962a4216
RS
1180(defun iswitchb-buffer-other-frame ()
1181 "Switch to another buffer and show it in another frame.
1182The buffer name is selected interactively by typing a substring.
6c56c80b 1183For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1184 (interactive)
1185 (setq iswitchb-method 'otherframe)
962a4216
RS
1186 (iswitchb))
1187
36a3b01c 1188;;; XEmacs hack for showing default buffer
962a4216
RS
1189
1190;; The first time we enter the minibuffer, Emacs puts up the default
ccd2f997 1191;; buffer to switch to, but XEmacs doesn't -- presumably there is a
36a3b01c
RS
1192;; subtle difference in the two versions of post-command-hook. The
1193;; default is shown for both whenever we delete all of our text
1194;; though, indicating its just a problem the first time we enter the
1195;; function. To solve this, we use another entry hook for emacs to
1196;; show the default the first time we enter the minibuffer.
962a4216 1197
6b0cc1b5 1198(defun iswitchb-init-XEmacs-trick ()
6c56c80b
RS
1199 "Display default buffer when first entering minibuffer.
1200This is a hack for XEmacs, and should really be handled by `iswitchb-exhibit'."
962a4216
RS
1201 (if (iswitchb-entryfn-p)
1202 (progn
36a3b01c 1203 (iswitchb-exhibit)
962a4216
RS
1204 (goto-char (point-min)))))
1205
36a3b01c 1206;; add this hook for XEmacs only.
2d839509 1207(if (featurep 'xemacs)
19db4308 1208 (add-hook 'iswitchb-minibuffer-setup-hook
6b0cc1b5 1209 'iswitchb-init-XEmacs-trick))
962a4216 1210
36a3b01c 1211;;; XEmacs / backspace key
ccd2f997 1212;; For some reason, if the backspace key is pressed in XEmacs, the
962a4216 1213;; line gets confused, so I've added a simple key definition to make
19db4308 1214;; backspace act like the normal delete key.
962a4216
RS
1215
1216(defun iswitchb-xemacs-backspacekey ()
1217 "Bind backspace to `backward-delete-char'."
1218 (define-key iswitchb-mode-map '[backspace] 'backward-delete-char)
181688f2 1219 (define-key iswitchb-mode-map '[(meta backspace)] 'backward-kill-word))
962a4216 1220
2d839509 1221(if (featurep 'xemacs)
19db4308 1222 (add-hook 'iswitchb-define-mode-map-hook
962a4216
RS
1223 'iswitchb-xemacs-backspacekey))
1224
962a4216
RS
1225;;; ICOMPLETE TYPE CODE
1226
1227(defun iswitchb-exhibit ()
6c56c80b 1228 "Find matching buffers and display a list in the minibuffer.
962a4216
RS
1229Copied from `icomplete-exhibit' with two changes:
12301. It prints a default buffer name when there is no text yet entered.
12312. It calls my completion routine rather than the standard completion."
962a4216 1232 (if iswitchb-use-mycompletion
600f9d03 1233 (let ((contents (buffer-substring (minibuffer-prompt-end) (point-max)))
962a4216
RS
1234 (buffer-undo-list t))
1235 (save-excursion
1236 (goto-char (point-max))
1237 ; Register the end of input, so we
1238 ; know where the extra stuff
1239 ; (match-status info) begins:
1240 (if (not (boundp 'iswitchb-eoinput))
1241 ;; In case it got wiped out by major mode business:
1242 (make-local-variable 'iswitchb-eoinput))
1243 (setq iswitchb-eoinput (point))
1244 ;; Update the list of matches
1245 (setq iswitchb-text contents)
1246 (iswitchb-set-matches)
1247 (setq iswitchb-rescan t)
1248 (iswitchb-set-common-completion)
1249
1250 ;; Insert the match-status information:
f1180544 1251 (insert (iswitchb-completions
b21688f0 1252 contents))))))
26119624 1253
c4ae2d51
JW
1254(eval-when-compile
1255 (defvar most-len)
1256 (defvar most-is-exact))
1257
c80d9534
JW
1258(defun iswitchb-output-completion (com)
1259 (if (= (length com) most-len)
1260 ;; Most is one exact match,
1261 ;; note that and leave out
1262 ;; for later indication:
1263 (ignore
1264 (setq most-is-exact t))
1265 (substring com most-len)))
1266
b21688f0 1267(defun iswitchb-completions (name)
962a4216
RS
1268 "Return the string that is displayed after the user's text.
1269Modified from `icomplete-completions'."
f1180544 1270
962a4216
RS
1271 (let ((comps iswitchb-matches)
1272 ; "-determined" - only one candidate
b21688f0
EZ
1273 (open-bracket-determined "[")
1274 (close-bracket-determined "]")
962a4216
RS
1275 ;"-prospects" - more than one candidate
1276 (open-bracket-prospects "{")
1277 (close-bracket-prospects "}")
181688f2 1278 first)
962a4216 1279
b21688f0 1280 (if (and iswitchb-use-faces comps)
962a4216
RS
1281 (progn
1282 (setq first (car comps))
1283 (setq first (format "%s" first))
1284 (put-text-property 0 (length first) 'face
19db4308 1285 (if (= (length comps) 1)
b21688f0 1286 (if iswitchb-invalid-regexp
54907cdc
KS
1287 'iswitchb-invalid-regexp
1288 'iswitchb-single-match)
1289 'iswitchb-current-match)
19db4308 1290 first)
181688f2 1291 (setq comps (cons first (cdr comps)))))
962a4216 1292
c4ae2d51
JW
1293 ;; If no buffers matched, and virtual buffers are being used, then
1294 ;; consult the list of past visited files, to see if we can find
1295 ;; the file which the user might thought was still open.
1296 (when (and iswitchb-use-virtual-buffers (null comps)
1297 recentf-list)
1298 (setq iswitchb-virtual-buffers nil)
1299 (let ((head recentf-list) name)
1300 (while head
1301 (if (and (setq name (file-name-nondirectory (car head)))
1302 (string-match (if iswitchb-regexp
1303 iswitchb-text
1304 (regexp-quote iswitchb-text)) name)
1305 (null (get-file-buffer (car head)))
1306 (not (assoc name iswitchb-virtual-buffers))
1307 (not (iswitchb-ignore-buffername-p name))
1308 (file-exists-p (car head)))
1309 (setq iswitchb-virtual-buffers
1310 (cons (cons name (car head))
1311 iswitchb-virtual-buffers)))
1312 (setq head (cdr head)))
1313 (setq iswitchb-virtual-buffers (nreverse iswitchb-virtual-buffers)
1314 comps (mapcar 'car iswitchb-virtual-buffers))
1315 (let ((comp comps))
1316 (while comp
1317 (put-text-property 0 (length (car comp))
54907cdc 1318 'face 'iswitchb-virtual-matches
c4ae2d51
JW
1319 (car comp))
1320 (setq comp (cdr comp))))))
1321
962a4216
RS
1322 (cond ((null comps) (format " %sNo match%s"
1323 open-bracket-determined
1324 close-bracket-determined))
1325
b21688f0
EZ
1326 (iswitchb-invalid-regexp
1327 (concat " " (car comps)))
1328 ((null (cdr comps)) ;one match
1329 (concat
1330 (if (if (not iswitchb-regexp)
1331 (= (length name)
1332 (length (car comps)))
1333 (string-match name (car comps))
1334 (string-equal (match-string 0 (car comps))
1335 (car comps)))
1336 ""
1337 (concat open-bracket-determined
19db4308 1338 ;; when there is one match, show the
962a4216
RS
1339 ;; matching buffer name in full
1340 (car comps)
b21688f0
EZ
1341 close-bracket-determined))
1342 (if (not iswitchb-use-faces) " [Matched]")))
962a4216 1343 (t ;multiple matches
c80d9534
JW
1344 (if (and iswitchb-max-to-show
1345 (> (length comps) iswitchb-max-to-show))
1346 (setq comps
1347 (append
5f5d410a
JW
1348 (let ((res nil)
1349 (comp comps)
1350 (end (/ iswitchb-max-to-show 2)))
1351 (while (>= (setq end (1- end)) 0)
1352 (setq res (cons (car comp) res)
1353 comp (cdr comp)))
1354 (nreverse res))
c80d9534 1355 (list "...")
5f5d410a
JW
1356 (nthcdr (- (length comps)
1357 (/ iswitchb-max-to-show 2)) comps))))
962a4216
RS
1358 (let* (
1359 ;;(most (try-completion name candidates predicate))
1360 (most nil)
1361 (most-len (length most))
1362 most-is-exact
c4ae2d51
JW
1363 (alternatives
1364 (mapconcat (if most 'iswitchb-output-completion
1365 'identity) comps ",")))
962a4216
RS
1366
1367 (concat
1368
1369 ;; put in common completion item -- what you get by
1370 ;; pressing tab
4e141ed7
SE
1371 (if (and (stringp iswitchb-common-match-string)
1372 (> (length iswitchb-common-match-string) (length name)))
962a4216 1373 (concat open-bracket-determined
19db4308 1374 (substring iswitchb-common-match-string
962a4216 1375 (length name))
181688f2 1376 close-bracket-determined))
962a4216
RS
1377 ;; end of partial matches...
1378
1379 ;; think this bit can be ignored.
1380 (and (> most-len (length name))
1381 (concat open-bracket-determined
1382 (substring most (length name))
1383 close-bracket-determined))
f1180544 1384
962a4216
RS
1385 ;; list all alternatives
1386 open-bracket-prospects
1387 (if most-is-exact
1388 (concat "," alternatives)
1389 alternatives)
181688f2 1390 close-bracket-prospects))))))
962a4216
RS
1391
1392(defun iswitchb-minibuffer-setup ()
6c56c80b
RS
1393 "Set up minibuffer for `iswitchb-buffer'.
1394Copied from `icomplete-minibuffer-setup-hook'."
8ae3ef6e
SM
1395 (when (iswitchb-entryfn-p)
1396 (set (make-local-variable 'iswitchb-use-mycompletion) t)
1397 (add-hook 'pre-command-hook 'iswitchb-pre-command nil t)
1398 (add-hook 'post-command-hook 'iswitchb-post-command nil t)
1399 (run-hooks 'iswitchb-minibuffer-setup-hook)))
962a4216
RS
1400
1401(defun iswitchb-pre-command ()
6c56c80b 1402 "Run before command in `iswitchb-buffer'."
962a4216
RS
1403 (iswitchb-tidy))
1404
962a4216 1405(defun iswitchb-post-command ()
6c56c80b 1406 "Run after command in `iswitchb-buffer'."
181688f2 1407 (iswitchb-exhibit))
962a4216
RS
1408
1409(defun iswitchb-tidy ()
1410 "Remove completions display, if any, prior to new user input.
1411Copied from `icomplete-tidy'."
1412
1413 (if (and (boundp 'iswitchb-eoinput)
1414 iswitchb-eoinput)
f1180544 1415
962a4216
RS
1416 (if (> iswitchb-eoinput (point-max))
1417 ;; Oops, got rug pulled out from under us - reinit:
1418 (setq iswitchb-eoinput (point-max))
1419 (let ((buffer-undo-list buffer-undo-list )) ; prevent entry
1420 (delete-region iswitchb-eoinput (point-max))))
f1180544 1421
962a4216
RS
1422 ;; Reestablish the local variable 'cause minibuffer-setup is weird:
1423 (make-local-variable 'iswitchb-eoinput)
1424 (setq iswitchb-eoinput 1)))
1425
962a4216 1426(defun iswitchb-entryfn-p ()
26119624 1427 "Return non-nil if we are using `iswitchb-buffer'."
c7b89861 1428 (eq iswitchb-minibuf-depth (minibuffer-depth)))
ccd2f997 1429
962a4216 1430(defun iswitchb-summaries-to-end ()
6c56c80b
RS
1431 "Move the summaries to the end of the list.
1432This is an example function which can be hooked on to
1433`iswitchb-make-buflist-hook'. Any buffer matching the regexps
1434`Summary' or `output\*$'are put to the end of the list."
19db4308
DL
1435 (let ((summaries (delq nil
1436 (mapcar
1437 (lambda (x)
1438 (if (string-match "Summary\\|output\\*$" x)
1439 x))
1440 iswitchb-temp-buflist))))
36a3b01c 1441 (iswitchb-to-end summaries)))
962a4216 1442
8097dd15
GM
1443(defun iswitchb-case ()
1444 "Return non-nil iff we should ignore case when matching.
1445See the variable `iswitchb-case' for details."
1446 (if iswitchb-case
2d839509 1447 (if (featurep 'xemacs)
8097dd15
GM
1448 (isearch-no-upper-case-p iswitchb-text)
1449 (isearch-no-upper-case-p iswitchb-text t))))
1450
19db4308 1451;;;###autoload
8ae3ef6e 1452(define-minor-mode iswitchb-mode
19db4308
DL
1453 "Toggle Iswitchb global minor mode.
1454With arg, turn Iswitchb mode on if and only iff ARG is positive.
1455This mode enables switching between buffers using substrings. See
1456`iswitchb' for details."
8ae3ef6e 1457 nil nil iswitchb-global-map :global t :group 'iswitchb
19db4308
DL
1458 (if iswitchb-mode
1459 (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)
8ae3ef6e 1460 (remove-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)))
19db4308 1461
962a4216
RS
1462(provide 'iswitchb)
1463
561ec225 1464;; arch-tag: d74198ae-753f-44f2-b34f-0c515398d90a
6c56c80b 1465;;; iswitchb.el ends here