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