Don't quote lambda expressions with `quote'.
[bpt/emacs.git] / lisp / iswitchb.el
CommitLineData
6c56c80b 1;;; iswitchb.el --- switch between buffers using substrings
962a4216 2
73b0cd50 3;; Copyright (C) 1996-1997, 2000-2011 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
962a4216
RS
125;;; Customisation
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
EZ
165;; font-lock is used to highlight the first matching buffer. To
166;; switch this off, set (setq iswitchb-use-faces nil). Colouring of
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
962a4216
RS
236;;; Acknowledgements
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
962a4216
RS
375(defvar iswitchb-all-frames 'visible
376 "*Argument to pass to `walk-windows' when finding visible buffers.
377See documentation of `walk-windows' for useful values.")
378
6b0cc1b5 379(defcustom iswitchb-minibuffer-setup-hook nil
19db4308 380 "Iswitchb-specific customization of minibuffer setup.
962a4216 381
4837b516 382This hook is run during minibuffer setup if `iswitchb' is active.
33a316ba
SE
383For instance:
384\(add-hook 'iswitchb-minibuffer-setup-hook
385 '\(lambda () (set (make-local-variable 'max-mini-window-height) 3)))
386will constrain the minibuffer to a maximum height of 3 lines when
387iswitchb is running."
6b0cc1b5
SE
388 :type 'hook
389 :group 'iswitchb)
390
54907cdc 391(defface iswitchb-single-match
b21688f0
EZ
392 '((t
393 (:inherit font-lock-comment-face)))
394 "Iswitchb face for single matching buffer name."
395 :version "22.1"
396 :group 'iswitchb)
397
54907cdc 398(defface iswitchb-current-match
b21688f0
EZ
399 '((t
400 (:inherit font-lock-function-name-face)))
401 "Iswitchb face for current matching buffer name."
402 :version "22.1"
403 :group 'iswitchb)
404
54907cdc 405(defface iswitchb-virtual-matches
b21688f0
EZ
406 '((t
407 (:inherit font-lock-builtin-face)))
408 "Iswitchb face for matching virtual buffer names.
409See also `iswitchb-use-virtual-buffers'."
410 :version "22.1"
411 :group 'iswitchb)
412
54907cdc 413(defface iswitchb-invalid-regexp
b21688f0
EZ
414 '((t
415 (:inherit font-lock-warning-face)))
416 "Iswitchb face for indicating invalid regexp. "
417 :version "22.1"
418 :group 'iswitchb)
419
6b0cc1b5
SE
420;; Do we need the variable iswitchb-use-mycompletion?
421
6b0cc1b5
SE
422;;; Internal Variables
423
424(defvar iswitchb-method nil
19db4308 425 "Stores the method for viewing the selected buffer.
6b0cc1b5
SE
426Its value is one of `samewindow', `otherwindow', `display', `otherframe',
427`maybe-frame' or `always-frame'. See `iswitchb-default-method' for
428details of values.")
962a4216
RS
429
430(defvar iswitchb-eoinput 1
431 "Point where minibuffer input ends and completion info begins.
6c56c80b 432Copied from `icomplete-eoinput'.")
962a4216
RS
433(make-variable-buffer-local 'iswitchb-eoinput)
434
962a4216
RS
435(defvar iswitchb-buflist nil
436 "Stores the current list of buffers that will be searched through.
437The list is ordered, so that the most recent buffers come first,
438although by default, the buffers visible in the current frame are put
439at the end of the list. Created by `iswitchb-make-buflist'.")
440
441;; todo -- is this necessary?
442
443(defvar iswitchb-use-mycompletion nil
19db4308 444 "Non-nil means use `iswitchb-buffer' completion feedback.
6c56c80b
RS
445Should only be set to t by iswitchb functions, so that it doesn't
446interfere with other minibuffer usage.")
962a4216 447
19db4308 448(defvar iswitchb-change-word-sub nil
962a4216
RS
449 "Private variable used by `iswitchb-word-matching-substring'.")
450
962a4216
RS
451(defvar iswitchb-common-match-string nil
452 "Stores the string that is common to all matching buffers.")
453
962a4216
RS
454(defvar iswitchb-rescan nil
455 "Non-nil means we need to regenerate the list of matching buffers.")
456
457(defvar iswitchb-text nil
458 "Stores the users string as it is typed in.")
459
460(defvar iswitchb-matches nil
ccd2f997 461 "List of buffers currently matching `iswitchb-text'.")
962a4216 462
19db4308
DL
463(defvar iswitchb-mode-map
464 (let ((map (make-sparse-keymap)))
465 (set-keymap-parent map minibuffer-local-map)
466 (define-key map "?" 'iswitchb-completion-help)
467 (define-key map "\C-s" 'iswitchb-next-match)
468 (define-key map "\C-r" 'iswitchb-prev-match)
469 (define-key map "\t" 'iswitchb-complete)
470 (define-key map "\C-j" 'iswitchb-select-buffer-text)
471 (define-key map "\C-t" 'iswitchb-toggle-regexp)
472 (define-key map "\C-x\C-f" 'iswitchb-find-file)
473 (define-key map "\C-c" 'iswitchb-toggle-case)
474 (define-key map "\C-k" 'iswitchb-kill-buffer)
475 (define-key map "\C-m" 'iswitchb-exit-minibuffer)
476 map)
477 "Minibuffer keymap for `iswitchb-buffer'.")
478
479(defvar iswitchb-global-map
480 (let ((map (make-sparse-keymap)))
51443e4f
SM
481 (dolist (b '((switch-to-buffer . iswitchb-buffer)
482 (switch-to-buffer-other-window . iswitchb-buffer-other-window)
483 (switch-to-buffer-other-frame . iswitchb-buffer-other-frame)
484 (display-buffer . iswitchb-display-buffer)))
485 (if (fboundp 'command-remapping)
486 (define-key map (vector 'remap (car b)) (cdr b))
487 (substitute-key-definition (car b) (cdr b) map global-map)))
19db4308 488 map)
971cb834 489 "Global keymap for `iswitchb-mode'.")
19db4308
DL
490
491(defvar iswitchb-history nil
6c56c80b 492 "History of buffers selected using `iswitchb-buffer'.")
962a4216 493
19db4308
DL
494(defvar iswitchb-exit nil
495 "Flag to monitor how `iswitchb-buffer' exits.
6c56c80b
RS
496If equal to `takeprompt', we use the prompt as the buffer name to be
497selected.")
962a4216
RS
498
499(defvar iswitchb-buffer-ignore-orig nil
500 "Stores original value of `iswitchb-buffer-ignore'.")
501
6b0cc1b5
SE
502(defvar iswitchb-default nil
503 "Default buffer for iswitchb.")
962a4216 504
02e526ad
SE
505;; The following variables are needed to keep the byte compiler quiet.
506(defvar iswitchb-require-match nil
507 "Non-nil if matching buffer must be selected.")
508
509(defvar iswitchb-temp-buflist nil
510 "Stores a temporary version of the buffer list being created.")
511
512(defvar iswitchb-bufs-in-frame nil
513 "List of the buffers visible in the current frame.")
514
c7b89861
EZ
515(defvar iswitchb-minibuf-depth nil
516 "Value we expect to be returned by `minibuffer-depth' in the minibuffer.")
517
b21688f0
EZ
518(defvar iswitchb-common-match-inserted nil
519 "Non-nil if we have just inserted a common match in the minibuffer.")
520
521(defvar iswitchb-invalid-regexp)
522
962a4216
RS
523;;; FUNCTIONS
524
19db4308 525;;; ISWITCHB KEYMAP
962a4216 526(defun iswitchb-define-mode-map ()
d7396512 527 "Set up the keymap for `iswitchb-buffer'."
962a4216
RS
528 (interactive)
529 (let (map)
ccd2f997 530 ;; generated every time so that it can inherit new functions.
962a4216
RS
531 ;;(or iswitchb-mode-map
532
533 (setq map (copy-keymap minibuffer-local-map))
534 (define-key map "?" 'iswitchb-completion-help)
535 (define-key map "\C-s" 'iswitchb-next-match)
536 (define-key map "\C-r" 'iswitchb-prev-match)
537 (define-key map "\t" 'iswitchb-complete)
538 (define-key map "\C-j" 'iswitchb-select-buffer-text)
539 (define-key map "\C-t" 'iswitchb-toggle-regexp)
36a3b01c 540 (define-key map "\C-x\C-f" 'iswitchb-find-file)
5311aad2 541 (define-key map "\C-n" 'iswitchb-toggle-ignore)
962a4216 542 (define-key map "\C-c" 'iswitchb-toggle-case)
36a3b01c 543 (define-key map "\C-k" 'iswitchb-kill-buffer)
ccd2f997 544 (define-key map "\C-m" 'iswitchb-exit-minibuffer)
962a4216 545 (setq iswitchb-mode-map map)
181688f2 546 (run-hooks 'iswitchb-define-mode-map-hook)))
f1180544 547
d7396512
JB
548(make-obsolete 'iswitchb-define-mode-map
549 "use M-x iswitchb-mode or customize the variable `iswitchb-mode'."
550 "21.1")
551
962a4216
RS
552;;; MAIN FUNCTION
553(defun iswitchb ()
554 "Switch to buffer matching a substring.
555As you type in a string, all of the buffers matching the string are
556displayed. When you have found the buffer you want, it can then be
557selected. As you type, most keys have their normal keybindings,
558except for the following:
559\\<iswitchb-mode-map>
560
561RET Select the buffer at the front of the list of matches. If the
6c56c80b 562list is empty, possibly prompt to create new buffer.
962a4216
RS
563
564\\[iswitchb-select-buffer-text] Select the current prompt as the buffer.
565If no buffer is found, prompt for a new one.
566
567\\[iswitchb-next-match] Put the first element at the end of the list.
568\\[iswitchb-prev-match] Put the last element at the start of the list.
19db4308 569\\[iswitchb-complete] Complete a common suffix to the current string that
962a4216
RS
570matches all buffers. If there is only one match, select that buffer.
571If there is no common suffix, show a list of all matching buffers
572in a separate window.
ccd2f997 573\\[iswitchb-toggle-regexp] Toggle regexp searching.
962a4216 574\\[iswitchb-toggle-case] Toggle case-sensitive searching of buffer names.
36a3b01c 575\\[iswitchb-completion-help] Show list of matching buffers in separate window.
19db4308 576\\[iswitchb-find-file] Exit iswitchb and drop into `find-file'.
36a3b01c 577\\[iswitchb-kill-buffer] Kill buffer at head of buffer list."
962a4216
RS
578 ;;\\[iswitchb-toggle-ignore] Toggle ignoring certain buffers (see \
579 ;;`iswitchb-buffer-ignore')
f1180544 580
8ae3ef6e 581 (let* ((prompt "iswitch ")
b21688f0 582 iswitchb-invalid-regexp
8ae3ef6e 583 (buf (iswitchb-read-buffer prompt)))
ccd2f997 584
ccd2f997
KH
585 ;;(message "chosen text %s" iswitchb-final-text)
586 ;; Choose the buffer name: either the text typed in, or the head
587 ;; of the list of matches
588
589 (cond ( (eq iswitchb-exit 'findfile)
590 (call-interactively 'find-file))
b21688f0
EZ
591 (iswitchb-invalid-regexp
592 (message "Won't make invalid regexp named buffer"))
ccd2f997
KH
593 (t
594 ;; View the buffer
c6e5b93f 595 ;;(message "go to buf %s" buf)
ccd2f997
KH
596 ;; Check buf is non-nil.
597 (if buf
598 (if (get-buffer buf)
599 ;; buffer exists, so view it and then exit
600 (iswitchb-visit-buffer buf)
601 ;; else buffer doesn't exist
602 (iswitchb-possible-new-buffer buf)))
181688f2 603 ))))
ccd2f997 604
c4ae2d51
JW
605(defun iswitchb-read-buffer (prompt &optional default require-match
606 start matches-set)
ccd2f997 607 "Replacement for the built-in `read-buffer'.
19db4308 608Return the name of a buffer selected.
c4ae2d51
JW
609PROMPT is the prompt to give to the user.
610DEFAULT if given is the default buffer to be selected, which will
611go to the front of the list.
252ca122 612If REQUIRE-MATCH is non-nil, an existing buffer must be selected.
c4ae2d51
JW
613If START is a string, the selection process is started with that
614string.
615If MATCHES-SET is non-nil, the buflist is not updated before
616the selection process begins. Used by isearchb.el."
962a4216
RS
617 (let
618 (
962a4216
RS
619 buf-sel
620 iswitchb-final-text
962a4216 621 (icomplete-mode nil) ;; prevent icomplete starting up
b21688f0 622 )
ccd2f997 623
962a4216 624 (iswitchb-define-mode-map)
962a4216 625 (setq iswitchb-exit nil)
6b0cc1b5
SE
626 (setq iswitchb-default
627 (if (bufferp default)
628 (buffer-name default)
629 default))
c4ae2d51
JW
630 (setq iswitchb-text (or start ""))
631 (unless matches-set
632 (setq iswitchb-rescan t)
633 (iswitchb-make-buflist iswitchb-default)
634 (iswitchb-set-matches))
19db4308 635 (let
ccd2f997 636 ((minibuffer-local-completion-map iswitchb-mode-map)
c7b89861
EZ
637 ;; Record the minibuffer depth that we expect to find once
638 ;; the minibuffer is set up and iswitchb-entryfn-p is called.
639 (iswitchb-minibuf-depth (1+ (minibuffer-depth)))
181688f2 640 (iswitchb-require-match require-match))
36a3b01c 641 ;; prompt the user for the buffer name
19db4308 642 (setq iswitchb-final-text (completing-read
c4ae2d51 643 prompt ;the prompt
660e161f 644 '(("dummy" . 1)) ;table
c4ae2d51
JW
645 nil ;predicate
646 nil ;require-match [handled elsewhere]
647 start ;initial-contents
ccd2f997 648 'iswitchb-history)))
4dddd07f
SE
649 (if (and (not (eq iswitchb-exit 'usefirst))
650 (get-buffer iswitchb-final-text))
8ae3ef6e 651 ;; This happens for example if the buffer was chosen with the mouse.
c4ae2d51
JW
652 (setq iswitchb-matches (list iswitchb-final-text)
653 iswitchb-virtual-buffers nil))
654
655 ;; If no buffer matched, but a virtual buffer was selected, visit
656 ;; that file now and act as though that buffer had been selected.
657 (if (and iswitchb-virtual-buffers
658 (not (iswitchb-existing-buffer-p)))
4078fd57
SE
659 (let ((virt (car iswitchb-virtual-buffers))
660 (new-buf))
06b60517 661 ;; Keep the name of the buffer returned by find-file-noselect, as
4078fd57
SE
662 ;; the buffer 'virt' could be a symlink to a file of a different name.
663 (setq new-buf (buffer-name (find-file-noselect (cdr virt))))
664 (setq iswitchb-matches (list new-buf)
c4ae2d51 665 iswitchb-virtual-buffers nil)))
8ae3ef6e 666
ccd2f997 667 ;; Handling the require-match must be done in a better way.
c4ae2d51
JW
668 (if (and require-match
669 (not (iswitchb-existing-buffer-p)))
19db4308 670 (error "Must specify valid buffer"))
ccd2f997 671
c4ae2d51
JW
672 (if (or (eq iswitchb-exit 'takeprompt)
673 (null iswitchb-matches))
ccd2f997
KH
674 (setq buf-sel iswitchb-final-text)
675 ;; else take head of list
676 (setq buf-sel (car iswitchb-matches)))
f1180544 677
ccd2f997 678 ;; Or possibly choose the default buffer
19db4308 679 (if (equal iswitchb-final-text "")
c4ae2d51 680 (setq buf-sel (car iswitchb-matches)))
36a3b01c 681
ccd2f997 682 buf-sel))
36a3b01c 683
ccd2f997
KH
684(defun iswitchb-existing-buffer-p ()
685 "Return non-nil if there is a matching buffer."
686 (not (null iswitchb-matches)))
962a4216
RS
687
688;;; COMPLETION CODE
689
690(defun iswitchb-set-common-completion ()
6c56c80b
RS
691 "Find common completion of `iswitchb-text' in `iswitchb-matches'.
692The result is stored in `iswitchb-common-match-string'."
962a4216 693
d7396512 694 (let (val)
962a4216
RS
695 (setq iswitchb-common-match-string nil)
696 (if (and iswitchb-matches
6b0cc1b5 697 (not iswitchb-regexp) ;; testing
962a4216
RS
698 (stringp iswitchb-text)
699 (> (length iswitchb-text) 0))
700 (if (setq val (iswitchb-find-common-substring
701 iswitchb-matches iswitchb-text))
702 (setq iswitchb-common-match-string val)))
181688f2 703 val))
962a4216
RS
704
705(defun iswitchb-complete ()
706 "Try and complete the current pattern amongst the buffer names."
707 (interactive)
708 (let (res)
709 (cond ((not iswitchb-matches)
c9403808 710 (run-hooks 'iswitchb-cannot-complete-hook))
b21688f0
EZ
711 (iswitchb-invalid-regexp
712 ;; Do nothing
713 )
ccd2f997 714 ((= 1 (length iswitchb-matches))
962a4216
RS
715 ;; only one choice, so select it.
716 (exit-minibuffer))
f1180544 717
962a4216
RS
718 (t
719 ;; else there could be some completions
6b0cc1b5 720 (setq res iswitchb-common-match-string)
962a4216 721 (if (and (not (memq res '(t nil)))
36a3b01c 722 (not (equal res iswitchb-text)))
ccd2f997 723 ;; found something to complete, so put it in the minibuffer.
962a4216 724 (progn
b21688f0
EZ
725 (setq iswitchb-rescan nil
726 iswitchb-common-match-inserted t)
53811b42 727 (delete-region (minibuffer-prompt-end) (point))
962a4216
RS
728 (insert res))
729 ;; else nothing to complete
c9403808 730 (run-hooks 'iswitchb-cannot-complete-hook)
181688f2 731 )))))
962a4216
RS
732
733;;; TOGGLE FUNCTIONS
734
735(defun iswitchb-toggle-case ()
19db4308 736 "Toggle the value of variable `iswitchb-case'."
962a4216
RS
737 (interactive)
738 (setq iswitchb-case (not iswitchb-case))
739 ;; ask for list to be regenerated.
181688f2 740 (setq iswitchb-rescan t))
962a4216
RS
741
742(defun iswitchb-toggle-regexp ()
743 "Toggle the value of `iswitchb-regexp'."
744 (interactive)
745 (setq iswitchb-regexp (not iswitchb-regexp))
746 ;; ask for list to be regenerated.
181688f2 747 (setq iswitchb-rescan t))
962a4216
RS
748
749(defun iswitchb-toggle-ignore ()
750 "Toggle ignoring buffers specified with `iswitchb-buffer-ignore'."
751 (interactive)
752 (if iswitchb-buffer-ignore
753 (progn
754 (setq iswitchb-buffer-ignore-orig iswitchb-buffer-ignore)
181688f2 755 (setq iswitchb-buffer-ignore nil))
962a4216 756 ;; else
181688f2 757 (setq iswitchb-buffer-ignore iswitchb-buffer-ignore-orig))
6b0cc1b5 758 (iswitchb-make-buflist iswitchb-default)
962a4216 759 ;; ask for list to be regenerated.
181688f2 760 (setq iswitchb-rescan t))
962a4216 761
ccd2f997
KH
762(defun iswitchb-exit-minibuffer ()
763 "Exit minibuffer, but make sure we have a match if one is needed."
764 (interactive)
765 (if (or (not iswitchb-require-match)
766 (iswitchb-existing-buffer-p))
4dddd07f
SE
767 (progn
768 (setq iswitchb-exit 'usefirst)
769 (throw 'exit nil))))
962a4216
RS
770
771(defun iswitchb-select-buffer-text ()
6c56c80b
RS
772 "Select the buffer named by the prompt.
773If no buffer exactly matching the prompt exists, maybe create a new one."
962a4216
RS
774 (interactive)
775 (setq iswitchb-exit 'takeprompt)
776 (exit-minibuffer))
777
36a3b01c 778(defun iswitchb-find-file ()
19db4308 779 "Drop into `find-file' from buffer switching."
36a3b01c
RS
780 (interactive)
781 (setq iswitchb-exit 'findfile)
782 (exit-minibuffer))
783
d7396512 784(defvar recentf-list)
c4ae2d51 785
19db4308 786(defun iswitchb-next-match ()
962a4216
RS
787 "Put first element of `iswitchb-matches' at the end of the list."
788 (interactive)
36a3b01c 789 (let ((next (cadr iswitchb-matches)))
c4ae2d51
JW
790 (if (and (null next) iswitchb-virtual-buffers)
791 (setq recentf-list
792 (iswitchb-chop recentf-list
793 (cdr (cadr iswitchb-virtual-buffers))))
794 (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist next)))
181688f2 795 (setq iswitchb-rescan t)))
962a4216 796
19db4308 797(defun iswitchb-prev-match ()
962a4216
RS
798 "Put last element of `iswitchb-matches' at the front of the list."
799 (interactive)
36a3b01c 800 (let ((prev (car (last iswitchb-matches))))
c4ae2d51
JW
801 (if (and (null prev) iswitchb-virtual-buffers)
802 (setq recentf-list
803 (iswitchb-chop recentf-list
804 (cdr (car (last iswitchb-virtual-buffers)))))
805 (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist prev)))
181688f2 806 (setq iswitchb-rescan t)))
36a3b01c
RS
807
808(defun iswitchb-chop (list elem)
809 "Remove all elements before ELEM and put them at the end of LIST."
810 (let ((ret nil)
811 (next nil)
812 (sofar nil))
813 (while (not ret)
814 (setq next (car list))
815 (if (equal next elem)
816 (setq ret (append list (nreverse sofar)))
817 ;; else
818 (progn
819 (setq list (cdr list))
820 (setq sofar (cons next sofar)))))
821 ret))
962a4216 822
962a4216
RS
823;;; CREATE LIST OF ALL CURRENT BUFFERS
824
ccd2f997 825(defun iswitchb-make-buflist (default)
6c56c80b 826 "Set `iswitchb-buflist' to the current list of buffers.
36a3b01c 827Currently visible buffers are put at the end of the list.
19db4308 828The hook `iswitchb-make-buflist-hook' is run after the list has been
36a3b01c 829created to allow the user to further modify the order of the buffer names
ccd2f997
KH
830in this list. If DEFAULT is non-nil, and corresponds to an existing buffer,
831it is put to the start of the list."
19db4308 832 (setq iswitchb-buflist
36a3b01c 833 (let* ((iswitchb-current-buffers (iswitchb-get-buffers-in-frames))
ceba0dac
GM
834 (iswitchb-temp-buflist
835 (delq nil
836 (mapcar
837 (lambda (x)
838 (let ((b-name (buffer-name x)))
839 (if (not
840 (or
841 (iswitchb-ignore-buffername-p b-name)
842 (memq b-name iswitchb-current-buffers)))
843 b-name)))
844 (buffer-list (and iswitchb-use-frame-buffer-list
845 (selected-frame)))))))
846 (setq iswitchb-temp-buflist
847 (nconc iswitchb-temp-buflist iswitchb-current-buffers))
962a4216 848 (run-hooks 'iswitchb-make-buflist-hook)
ceba0dac 849 ;; Should this be after the hooks, or should the hooks be the
ccd2f997
KH
850 ;; final thing to be run?
851 (if default
852 (progn
19db4308 853 (setq iswitchb-temp-buflist
02e526ad 854 (delete default iswitchb-temp-buflist))
19db4308 855 (setq iswitchb-temp-buflist
02e526ad
SE
856 (cons default iswitchb-temp-buflist))))
857 iswitchb-temp-buflist)))
962a4216 858
36a3b01c 859(defun iswitchb-to-end (lst)
02e526ad 860 "Move the elements from LST to the end of `iswitchb-temp-buflist'."
561ec225
SM
861 (dolist (elem lst)
862 (setq iswitchb-temp-buflist (delq elem iswitchb-temp-buflist)))
ceba0dac 863 (setq iswitchb-temp-buflist (nconc iswitchb-temp-buflist lst)))
962a4216 864
962a4216 865(defun iswitchb-get-buffers-in-frames (&optional current)
962a4216 866 "Return the list of buffers that are visible in the current frame.
19db4308 867If optional argument CURRENT is given, restrict searching to the
962a4216
RS
868current frame, rather than all frames, regardless of value of
869`iswitchb-all-frames'."
962a4216 870 (let ((iswitchb-bufs-in-frame nil))
962a4216 871 (walk-windows 'iswitchb-get-bufname nil
19db4308 872 (if current
962a4216
RS
873 nil
874 iswitchb-all-frames))
875 iswitchb-bufs-in-frame))
876
962a4216
RS
877(defun iswitchb-get-bufname (win)
878 "Used by `iswitchb-get-buffers-in-frames' to walk through all windows."
ae5ac7d0
RS
879 (let ((buf (buffer-name (window-buffer win))))
880 (if (not (member buf iswitchb-bufs-in-frame))
881 ;; Only add buf if it is not already in list.
882 ;; This prevents same buf in two different windows being
883 ;; put into the list twice.
884 (setq iswitchb-bufs-in-frame
885 (cons buf iswitchb-bufs-in-frame)))))
962a4216 886
962a4216
RS
887;;; FIND MATCHING BUFFERS
888
889(defun iswitchb-set-matches ()
890 "Set `iswitchb-matches' to the list of buffers matching prompt."
962a4216
RS
891 (if iswitchb-rescan
892 (setq iswitchb-matches
d7396512 893 (let ((buflist iswitchb-buflist))
36a3b01c 894 (iswitchb-get-matched-buffers iswitchb-text iswitchb-regexp
c4ae2d51
JW
895 buflist))
896 iswitchb-virtual-buffers nil)))
36a3b01c
RS
897
898(defun iswitchb-get-matched-buffers (regexp
899 &optional string-format buffer-list)
6b0cc1b5
SE
900 "Return buffers matching REGEXP.
901If STRING-FORMAT is nil, consider REGEXP as just a string.
6c56c80b 902BUFFER-LIST can be list of buffers or list of strings."
d7396512 903 (let ((case-fold-search (iswitchb-case))
561ec225
SM
904 name ret)
905 (if (null string-format) (setq regexp (regexp-quote regexp)))
b21688f0 906 (setq iswitchb-invalid-regexp nil)
561ec225
SM
907 (condition-case error
908 (dolist (x buffer-list (nreverse ret))
909 (setq name (if (stringp x) x (buffer-name x)))
910 (when (and (string-match regexp name)
911 (not (iswitchb-ignore-buffername-p name)))
912 (push name ret)))
913 (invalid-regexp
914 (setq iswitchb-invalid-regexp t)
915 (cdr error)))))
962a4216
RS
916
917(defun iswitchb-ignore-buffername-p (bufname)
918 "Return t if the buffer BUFNAME should be ignored."
919 (let ((data (match-data))
920 (re-list iswitchb-buffer-ignore)
921 ignorep
181688f2 922 nextstr)
962a4216
RS
923 (while re-list
924 (setq nextstr (car re-list))
925 (cond
926 ((stringp nextstr)
927 (if (string-match nextstr bufname)
928 (progn
929 (setq ignorep t)
930 (setq re-list nil))))
1a1dd431 931 ((functionp nextstr)
962a4216
RS
932 (if (funcall nextstr bufname)
933 (progn
934 (setq ignorep t)
181688f2 935 (setq re-list nil)))))
962a4216 936 (setq re-list (cdr re-list)))
25c80f5c 937 (set-match-data data)
962a4216
RS
938
939 ;; return the result
181688f2 940 ignorep))
962a4216 941
962a4216
RS
942(defun iswitchb-word-matching-substring (word)
943 "Return part of WORD before 1st match to `iswitchb-change-word-sub'.
944If `iswitchb-change-word-sub' cannot be found in WORD, return nil."
8097dd15 945 (let ((case-fold-search (iswitchb-case)))
962a4216
RS
946 (let ((m (string-match iswitchb-change-word-sub word)))
947 (if m
948 (substring word m)
949 ;; else no match
950 nil))))
951
962a4216
RS
952(defun iswitchb-find-common-substring (lis subs)
953 "Return common string following SUBS in each element of LIS."
954 (let (res
955 alist
181688f2 956 iswitchb-change-word-sub)
962a4216
RS
957 (setq iswitchb-change-word-sub
958 (if iswitchb-regexp
959 subs
960 (regexp-quote subs)))
961 (setq res (mapcar 'iswitchb-word-matching-substring lis))
ccd2f997 962 (setq res (delq nil res)) ;; remove any nil elements (shouldn't happen)
962a4216
RS
963 (setq alist (mapcar 'iswitchb-makealist res)) ;; could use an OBARRAY
964
965 ;; try-completion returns t if there is an exact match.
8097dd15 966 (let ((completion-ignore-case (iswitchb-case)))
962a4216 967
181688f2 968 (try-completion subs alist))))
962a4216
RS
969
970(defun iswitchb-makealist (res)
971 "Return dotted pair (RES . 1)."
972 (cons res 1))
973
974;; from Wayne Mesard <wmesard@esd.sgi.com>
975(defun iswitchb-rotate-list (lis)
19db4308 976 "Destructively remove the last element from LIS.
962a4216
RS
977Return the modified list with the last element prepended to it."
978 (if (<= (length lis) 1)
979 lis
980 (let ((las lis)
981 (prev lis))
982 (while (consp (cdr las))
983 (setq prev las
984 las (cdr las)))
985 (setcdr prev nil)
181688f2 986 (cons (car las) lis))))
962a4216
RS
987
988(defun iswitchb-completion-help ()
8ae3ef6e 989 "Show possible completions in a *Completions* buffer."
962a4216 990 ;; we could allow this buffer to be used to select match, but I think
36a3b01c 991 ;; choose-completion-string will need redefining, so it just inserts
19db4308 992 ;; choice with out any previous input.
962a4216 993 (interactive)
36a3b01c 994 (setq iswitchb-rescan nil)
8ae3ef6e
SM
995 (let ((buf (current-buffer))
996 (temp-buf "*Completions*")
997 (win))
ccd2f997 998
b21688f0
EZ
999 (if (and (eq last-command this-command)
1000 (not iswitchb-common-match-inserted))
ccd2f997
KH
1001 ;; scroll buffer
1002 (progn
1003 (set-buffer temp-buf)
1004 (setq win (get-buffer-window temp-buf))
1005 (if (pos-visible-in-window-p (point-max) win)
1006 (set-window-start win (point-min))
1007 (scroll-other-window))
181688f2 1008 (set-buffer buf))
f1180544 1009
ccd2f997 1010 (with-output-to-temp-buffer temp-buf
2d839509 1011 (if (featurep 'xemacs)
f1180544 1012
ccd2f997
KH
1013 ;; XEmacs extents are put on by default, doesn't seem to be
1014 ;; any way of switching them off.
d5e63715 1015 (display-completion-list (or iswitchb-matches iswitchb-buflist)
ccd2f997 1016 :help-string "iswitchb "
19db4308 1017 :activate-callback
06b60517 1018 (lambda (_x _y _z)
19db4308 1019 (message "doesn't work yet, sorry!")))
ccd2f997 1020 ;; else running Emacs
d5e63715 1021 (display-completion-list (or iswitchb-matches iswitchb-buflist))))
b21688f0 1022 (setq iswitchb-common-match-inserted nil))))
ccd2f997 1023
36a3b01c
RS
1024;;; KILL CURRENT BUFFER
1025
1026(defun iswitchb-kill-buffer ()
ccd2f997 1027 "Kill the buffer at the head of `iswitchb-matches'."
36a3b01c 1028 (interactive)
e0143335
LL
1029 (let ((enable-recursive-minibuffers t)
1030 buf)
36a3b01c
RS
1031
1032 (setq buf (car iswitchb-matches))
1033 ;; check to see if buf is non-nil.
1034 (if buf
19677c71
LL
1035 (let ((bufobjs (mapcar (lambda (name)
1036 (or (get-buffer name) name))
1037 iswitchb-buflist)))
36a3b01c
RS
1038 (kill-buffer buf)
1039
1040 ;; Check if buffer exists. XEmacs gnuserv.el makes alias
1041 ;; for kill-buffer which does not return t if buffer is
1042 ;; killed, so we can't rely on kill-buffer return value.
1043 (if (get-buffer buf)
1044 ;; buffer couldn't be killed.
19db4308 1045 (setq iswitchb-rescan t)
e0143335
LL
1046 ;; Else `kill-buffer' succeeds so re-make the buffer list
1047 ;; taking into account packages like uniquify may rename
19677c71
LL
1048 ;; buffers, and try to preserve the ordering of buffers.
1049 (setq iswitchb-buflist
1050 (delq nil (mapcar (lambda (b)
1051 (if (bufferp b)
1052 (buffer-name b)
1053 b))
1054 bufobjs))))))))
36a3b01c 1055
962a4216
RS
1056;;; VISIT CHOSEN BUFFER
1057(defun iswitchb-visit-buffer (buffer)
1058 "Visit buffer named BUFFER according to `iswitchb-method'."
d7396512 1059 (let (win newframe)
962a4216
RS
1060 (cond
1061 ((eq iswitchb-method 'samewindow)
1062 (switch-to-buffer buffer))
1063
1064 ((memq iswitchb-method '(always-frame maybe-frame))
1065 (cond
1066 ((and (setq win (iswitchb-window-buffer-p buffer))
1067 (or (eq iswitchb-method 'always-frame)
1068 (y-or-n-p "Jump to frame? ")))
1069 (setq newframe (window-frame win))
2d839509 1070 (if (fboundp 'select-frame-set-input-focus)
4d8ae757
RS
1071 (select-frame-set-input-focus newframe)
1072 (raise-frame newframe)
1073 (select-frame newframe)
1074 )
1075 (select-window win))
962a4216
RS
1076 (t
1077 ;; No buffer in other frames...
1078 (switch-to-buffer buffer)
1079 )))
1080
962a4216
RS
1081 ((eq iswitchb-method 'otherwindow)
1082 (switch-to-buffer-other-window buffer))
1083
888472e0
RS
1084 ((eq iswitchb-method 'display)
1085 (display-buffer buffer))
1086
962a4216
RS
1087 ((eq iswitchb-method 'otherframe)
1088 (progn
1089 (switch-to-buffer-other-frame buffer)
2d839509 1090 (if (fboundp 'select-frame-set-input-focus)
4d8ae757 1091 (select-frame-set-input-focus (selected-frame)))
181688f2 1092 )))))
962a4216
RS
1093
1094(defun iswitchb-possible-new-buffer (buf)
1095 "Possibly create and visit a new buffer called BUF."
1096
1097 (let ((newbufcreated))
1098 (if (and iswitchb-newbuffer
1099 (or
1100 (not iswitchb-prompt-newbuffer)
f1180544 1101
962a4216
RS
1102 (and iswitchb-prompt-newbuffer
1103 (y-or-n-p
1104 (format
1105 "No buffer matching `%s', create one? "
1106 buf)))))
1107 ;; then create a new buffer
1108 (progn
1109 (setq newbufcreated (get-buffer-create buf))
1110 (if (fboundp 'set-buffer-major-mode)
1111 (set-buffer-major-mode newbufcreated))
1112 (iswitchb-visit-buffer newbufcreated))
1113 ;; else wont create new buffer
8a26c165 1114 (message "no buffer matching `%s'" buf))))
962a4216
RS
1115
1116(defun iswitchb-window-buffer-p (buffer)
6c56c80b
RS
1117 "Return window pointer if BUFFER is visible in another frame.
1118If BUFFER is visible in the current frame, return nil."
962a4216 1119 (interactive)
962a4216
RS
1120 (let ((blist (iswitchb-get-buffers-in-frames 'current)))
1121 ;;If the buffer is visible in current frame, return nil
1122 (if (memq buffer blist)
1123 nil
ccd2f997
KH
1124 ;; maybe in other frame or icon
1125 (get-buffer-window buffer 0) ; better than 'visible
962a4216
RS
1126 )))
1127
962a4216
RS
1128(defun iswitchb-buffer ()
1129 "Switch to another buffer.
1130
1131The buffer name is selected interactively by typing a substring. The
1132buffer is displayed according to `iswitchb-default-method' -- the
1133default is to show it in the same window, unless it is already visible
6c56c80b
RS
1134in another frame.
1135For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1136 (interactive)
1137 (setq iswitchb-method iswitchb-default-method)
ccd2f997 1138 (iswitchb))
962a4216 1139
962a4216
RS
1140(defun iswitchb-buffer-other-window ()
1141 "Switch to another buffer and show it in another window.
1142The buffer name is selected interactively by typing a substring.
6c56c80b 1143For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1144 (interactive)
1145 (setq iswitchb-method 'otherwindow)
ccd2f997 1146 (iswitchb))
962a4216 1147
888472e0
RS
1148(defun iswitchb-display-buffer ()
1149 "Display a buffer in another window but don't select it.
1150The buffer name is selected interactively by typing a substring.
1151For details of keybindings, do `\\[describe-function] iswitchb'."
1152 (interactive)
1153 (setq iswitchb-method 'display)
ccd2f997 1154 (iswitchb))
888472e0 1155
962a4216
RS
1156(defun iswitchb-buffer-other-frame ()
1157 "Switch to another buffer and show it in another frame.
1158The buffer name is selected interactively by typing a substring.
6c56c80b 1159For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1160 (interactive)
1161 (setq iswitchb-method 'otherframe)
962a4216
RS
1162 (iswitchb))
1163
36a3b01c 1164;;; XEmacs hack for showing default buffer
962a4216
RS
1165
1166;; The first time we enter the minibuffer, Emacs puts up the default
ccd2f997 1167;; buffer to switch to, but XEmacs doesn't -- presumably there is a
36a3b01c
RS
1168;; subtle difference in the two versions of post-command-hook. The
1169;; default is shown for both whenever we delete all of our text
1170;; though, indicating its just a problem the first time we enter the
1171;; function. To solve this, we use another entry hook for emacs to
1172;; show the default the first time we enter the minibuffer.
962a4216 1173
6b0cc1b5 1174(defun iswitchb-init-XEmacs-trick ()
6c56c80b
RS
1175 "Display default buffer when first entering minibuffer.
1176This is a hack for XEmacs, and should really be handled by `iswitchb-exhibit'."
962a4216
RS
1177 (if (iswitchb-entryfn-p)
1178 (progn
36a3b01c 1179 (iswitchb-exhibit)
962a4216
RS
1180 (goto-char (point-min)))))
1181
36a3b01c 1182;; add this hook for XEmacs only.
2d839509 1183(if (featurep 'xemacs)
19db4308 1184 (add-hook 'iswitchb-minibuffer-setup-hook
6b0cc1b5 1185 'iswitchb-init-XEmacs-trick))
962a4216 1186
36a3b01c 1187;;; XEmacs / backspace key
ccd2f997 1188;; For some reason, if the backspace key is pressed in XEmacs, the
962a4216 1189;; line gets confused, so I've added a simple key definition to make
19db4308 1190;; backspace act like the normal delete key.
962a4216
RS
1191
1192(defun iswitchb-xemacs-backspacekey ()
1193 "Bind backspace to `backward-delete-char'."
1194 (define-key iswitchb-mode-map '[backspace] 'backward-delete-char)
181688f2 1195 (define-key iswitchb-mode-map '[(meta backspace)] 'backward-kill-word))
962a4216 1196
2d839509 1197(if (featurep 'xemacs)
19db4308 1198 (add-hook 'iswitchb-define-mode-map-hook
962a4216
RS
1199 'iswitchb-xemacs-backspacekey))
1200
962a4216
RS
1201;;; ICOMPLETE TYPE CODE
1202
1203(defun iswitchb-exhibit ()
6c56c80b 1204 "Find matching buffers and display a list in the minibuffer.
962a4216
RS
1205Copied from `icomplete-exhibit' with two changes:
12061. It prints a default buffer name when there is no text yet entered.
12072. It calls my completion routine rather than the standard completion."
962a4216 1208 (if iswitchb-use-mycompletion
600f9d03 1209 (let ((contents (buffer-substring (minibuffer-prompt-end) (point-max)))
962a4216
RS
1210 (buffer-undo-list t))
1211 (save-excursion
1212 (goto-char (point-max))
1213 ; Register the end of input, so we
1214 ; know where the extra stuff
1215 ; (match-status info) begins:
1216 (if (not (boundp 'iswitchb-eoinput))
1217 ;; In case it got wiped out by major mode business:
1218 (make-local-variable 'iswitchb-eoinput))
1219 (setq iswitchb-eoinput (point))
1220 ;; Update the list of matches
1221 (setq iswitchb-text contents)
1222 (iswitchb-set-matches)
1223 (setq iswitchb-rescan t)
1224 (iswitchb-set-common-completion)
1225
1226 ;; Insert the match-status information:
f1180544 1227 (insert (iswitchb-completions
b21688f0 1228 contents))))))
26119624 1229
d7396512
JB
1230(defvar most-len)
1231(defvar most-is-exact)
c4ae2d51 1232
c80d9534
JW
1233(defun iswitchb-output-completion (com)
1234 (if (= (length com) most-len)
1235 ;; Most is one exact match,
1236 ;; note that and leave out
1237 ;; for later indication:
1238 (ignore
1239 (setq most-is-exact t))
1240 (substring com most-len)))
1241
b21688f0 1242(defun iswitchb-completions (name)
962a4216
RS
1243 "Return the string that is displayed after the user's text.
1244Modified from `icomplete-completions'."
f1180544 1245
962a4216
RS
1246 (let ((comps iswitchb-matches)
1247 ; "-determined" - only one candidate
b21688f0
EZ
1248 (open-bracket-determined "[")
1249 (close-bracket-determined "]")
962a4216
RS
1250 ;"-prospects" - more than one candidate
1251 (open-bracket-prospects "{")
1252 (close-bracket-prospects "}")
181688f2 1253 first)
962a4216 1254
b21688f0 1255 (if (and iswitchb-use-faces comps)
962a4216
RS
1256 (progn
1257 (setq first (car comps))
1258 (setq first (format "%s" first))
1259 (put-text-property 0 (length first) 'face
19db4308 1260 (if (= (length comps) 1)
b21688f0 1261 (if iswitchb-invalid-regexp
54907cdc
KS
1262 'iswitchb-invalid-regexp
1263 'iswitchb-single-match)
1264 'iswitchb-current-match)
19db4308 1265 first)
181688f2 1266 (setq comps (cons first (cdr comps)))))
962a4216 1267
c4ae2d51
JW
1268 ;; If no buffers matched, and virtual buffers are being used, then
1269 ;; consult the list of past visited files, to see if we can find
1270 ;; the file which the user might thought was still open.
1271 (when (and iswitchb-use-virtual-buffers (null comps)
e6d23bb5 1272 recentf-list)
c4ae2d51
JW
1273 (setq iswitchb-virtual-buffers nil)
1274 (let ((head recentf-list) name)
1275 (while head
1276 (if (and (setq name (file-name-nondirectory (car head)))
1277 (string-match (if iswitchb-regexp
1278 iswitchb-text
1279 (regexp-quote iswitchb-text)) name)
1280 (null (get-file-buffer (car head)))
1281 (not (assoc name iswitchb-virtual-buffers))
1282 (not (iswitchb-ignore-buffername-p name))
1283 (file-exists-p (car head)))
1284 (setq iswitchb-virtual-buffers
1285 (cons (cons name (car head))
1286 iswitchb-virtual-buffers)))
e6d23bb5
CY
1287 (setq head (cdr head)))
1288 (setq iswitchb-virtual-buffers (nreverse iswitchb-virtual-buffers)
1289 comps (mapcar 'car iswitchb-virtual-buffers))
c4ae2d51
JW
1290 (let ((comp comps))
1291 (while comp
1292 (put-text-property 0 (length (car comp))
54907cdc 1293 'face 'iswitchb-virtual-matches
c4ae2d51 1294 (car comp))
e6d23bb5 1295 (setq comp (cdr comp))))))
c4ae2d51 1296
962a4216
RS
1297 (cond ((null comps) (format " %sNo match%s"
1298 open-bracket-determined
1299 close-bracket-determined))
1300
b21688f0
EZ
1301 (iswitchb-invalid-regexp
1302 (concat " " (car comps)))
1303 ((null (cdr comps)) ;one match
1304 (concat
1305 (if (if (not iswitchb-regexp)
1306 (= (length name)
1307 (length (car comps)))
1308 (string-match name (car comps))
1309 (string-equal (match-string 0 (car comps))
1310 (car comps)))
1311 ""
1312 (concat open-bracket-determined
19db4308 1313 ;; when there is one match, show the
962a4216
RS
1314 ;; matching buffer name in full
1315 (car comps)
b21688f0
EZ
1316 close-bracket-determined))
1317 (if (not iswitchb-use-faces) " [Matched]")))
962a4216 1318 (t ;multiple matches
c80d9534
JW
1319 (if (and iswitchb-max-to-show
1320 (> (length comps) iswitchb-max-to-show))
1321 (setq comps
1322 (append
5f5d410a
JW
1323 (let ((res nil)
1324 (comp comps)
1325 (end (/ iswitchb-max-to-show 2)))
1326 (while (>= (setq end (1- end)) 0)
1327 (setq res (cons (car comp) res)
1328 comp (cdr comp)))
1329 (nreverse res))
c80d9534 1330 (list "...")
5f5d410a
JW
1331 (nthcdr (- (length comps)
1332 (/ iswitchb-max-to-show 2)) comps))))
962a4216
RS
1333 (let* (
1334 ;;(most (try-completion name candidates predicate))
1335 (most nil)
1336 (most-len (length most))
1337 most-is-exact
c4ae2d51
JW
1338 (alternatives
1339 (mapconcat (if most 'iswitchb-output-completion
6a0e4c60 1340 'identity) comps iswitchb-delim)))
962a4216
RS
1341
1342 (concat
1343
1344 ;; put in common completion item -- what you get by
1345 ;; pressing tab
4e141ed7
SE
1346 (if (and (stringp iswitchb-common-match-string)
1347 (> (length iswitchb-common-match-string) (length name)))
962a4216 1348 (concat open-bracket-determined
19db4308 1349 (substring iswitchb-common-match-string
962a4216 1350 (length name))
181688f2 1351 close-bracket-determined))
962a4216
RS
1352 ;; end of partial matches...
1353
1354 ;; think this bit can be ignored.
1355 (and (> most-len (length name))
1356 (concat open-bracket-determined
1357 (substring most (length name))
1358 close-bracket-determined))
f1180544 1359
962a4216
RS
1360 ;; list all alternatives
1361 open-bracket-prospects
1362 (if most-is-exact
6a0e4c60 1363 (concat iswitchb-delim alternatives)
962a4216 1364 alternatives)
181688f2 1365 close-bracket-prospects))))))
962a4216
RS
1366
1367(defun iswitchb-minibuffer-setup ()
6c56c80b
RS
1368 "Set up minibuffer for `iswitchb-buffer'.
1369Copied from `icomplete-minibuffer-setup-hook'."
8ae3ef6e
SM
1370 (when (iswitchb-entryfn-p)
1371 (set (make-local-variable 'iswitchb-use-mycompletion) t)
1372 (add-hook 'pre-command-hook 'iswitchb-pre-command nil t)
1373 (add-hook 'post-command-hook 'iswitchb-post-command nil t)
1374 (run-hooks 'iswitchb-minibuffer-setup-hook)))
962a4216
RS
1375
1376(defun iswitchb-pre-command ()
6c56c80b 1377 "Run before command in `iswitchb-buffer'."
962a4216
RS
1378 (iswitchb-tidy))
1379
962a4216 1380(defun iswitchb-post-command ()
6c56c80b 1381 "Run after command in `iswitchb-buffer'."
181688f2 1382 (iswitchb-exhibit))
962a4216
RS
1383
1384(defun iswitchb-tidy ()
1385 "Remove completions display, if any, prior to new user input.
1386Copied from `icomplete-tidy'."
1387
1388 (if (and (boundp 'iswitchb-eoinput)
1389 iswitchb-eoinput)
f1180544 1390
962a4216
RS
1391 (if (> iswitchb-eoinput (point-max))
1392 ;; Oops, got rug pulled out from under us - reinit:
1393 (setq iswitchb-eoinput (point-max))
1394 (let ((buffer-undo-list buffer-undo-list )) ; prevent entry
1395 (delete-region iswitchb-eoinput (point-max))))
f1180544 1396
962a4216
RS
1397 ;; Reestablish the local variable 'cause minibuffer-setup is weird:
1398 (make-local-variable 'iswitchb-eoinput)
1399 (setq iswitchb-eoinput 1)))
1400
962a4216 1401(defun iswitchb-entryfn-p ()
26119624 1402 "Return non-nil if we are using `iswitchb-buffer'."
c7b89861 1403 (eq iswitchb-minibuf-depth (minibuffer-depth)))
ccd2f997 1404
962a4216 1405(defun iswitchb-summaries-to-end ()
6c56c80b
RS
1406 "Move the summaries to the end of the list.
1407This is an example function which can be hooked on to
1408`iswitchb-make-buflist-hook'. Any buffer matching the regexps
1409`Summary' or `output\*$'are put to the end of the list."
19db4308
DL
1410 (let ((summaries (delq nil
1411 (mapcar
1412 (lambda (x)
1413 (if (string-match "Summary\\|output\\*$" x)
1414 x))
1415 iswitchb-temp-buflist))))
36a3b01c 1416 (iswitchb-to-end summaries)))
962a4216 1417
8097dd15 1418(defun iswitchb-case ()
4837b516 1419 "Return non-nil if we should ignore case when matching.
8097dd15
GM
1420See the variable `iswitchb-case' for details."
1421 (if iswitchb-case
2d839509 1422 (if (featurep 'xemacs)
8097dd15
GM
1423 (isearch-no-upper-case-p iswitchb-text)
1424 (isearch-no-upper-case-p iswitchb-text t))))
1425
19db4308 1426;;;###autoload
8ae3ef6e 1427(define-minor-mode iswitchb-mode
19db4308 1428 "Toggle Iswitchb global minor mode.
4837b516 1429With arg, turn Iswitchb mode on if ARG is positive, otherwise turn it off.
19db4308
DL
1430This mode enables switching between buffers using substrings. See
1431`iswitchb' for details."
8ae3ef6e 1432 nil nil iswitchb-global-map :global t :group 'iswitchb
19db4308
DL
1433 (if iswitchb-mode
1434 (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)
8ae3ef6e 1435 (remove-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)))
19db4308 1436
962a4216
RS
1437(provide 'iswitchb)
1438
6c56c80b 1439;;; iswitchb.el ends here