Spelling fixes.
[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
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
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))
c7015153 1113 ;; else won't 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 1120 (let ((blist (iswitchb-get-buffers-in-frames 'current)))
6c4cab03 1121 ;; If the buffer is visible in current frame, return nil
ade1b01c 1122 (unless (member buffer blist)
6c4cab03 1123 ;; maybe in other frame or icon
ccd2f997 1124 (get-buffer-window buffer 0) ; better than 'visible
962a4216
RS
1125 )))
1126
962a4216
RS
1127(defun iswitchb-buffer ()
1128 "Switch to another buffer.
1129
1130The buffer name is selected interactively by typing a substring. The
1131buffer is displayed according to `iswitchb-default-method' -- the
1132default is to show it in the same window, unless it is already visible
6c56c80b
RS
1133in another frame.
1134For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1135 (interactive)
1136 (setq iswitchb-method iswitchb-default-method)
ccd2f997 1137 (iswitchb))
962a4216 1138
962a4216
RS
1139(defun iswitchb-buffer-other-window ()
1140 "Switch to another buffer and show it in another window.
1141The buffer name is selected interactively by typing a substring.
6c56c80b 1142For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1143 (interactive)
1144 (setq iswitchb-method 'otherwindow)
ccd2f997 1145 (iswitchb))
962a4216 1146
888472e0
RS
1147(defun iswitchb-display-buffer ()
1148 "Display a buffer in another window but don't select it.
1149The buffer name is selected interactively by typing a substring.
1150For details of keybindings, do `\\[describe-function] iswitchb'."
1151 (interactive)
1152 (setq iswitchb-method 'display)
ccd2f997 1153 (iswitchb))
888472e0 1154
962a4216
RS
1155(defun iswitchb-buffer-other-frame ()
1156 "Switch to another buffer and show it in another frame.
1157The buffer name is selected interactively by typing a substring.
6c56c80b 1158For details of keybindings, do `\\[describe-function] iswitchb'."
962a4216
RS
1159 (interactive)
1160 (setq iswitchb-method 'otherframe)
962a4216
RS
1161 (iswitchb))
1162
36a3b01c 1163;;; XEmacs hack for showing default buffer
962a4216
RS
1164
1165;; The first time we enter the minibuffer, Emacs puts up the default
ccd2f997 1166;; buffer to switch to, but XEmacs doesn't -- presumably there is a
36a3b01c
RS
1167;; subtle difference in the two versions of post-command-hook. The
1168;; default is shown for both whenever we delete all of our text
1169;; though, indicating its just a problem the first time we enter the
1170;; function. To solve this, we use another entry hook for emacs to
1171;; show the default the first time we enter the minibuffer.
962a4216 1172
6b0cc1b5 1173(defun iswitchb-init-XEmacs-trick ()
6c56c80b
RS
1174 "Display default buffer when first entering minibuffer.
1175This is a hack for XEmacs, and should really be handled by `iswitchb-exhibit'."
962a4216
RS
1176 (if (iswitchb-entryfn-p)
1177 (progn
36a3b01c 1178 (iswitchb-exhibit)
962a4216
RS
1179 (goto-char (point-min)))))
1180
36a3b01c 1181;; add this hook for XEmacs only.
2d839509 1182(if (featurep 'xemacs)
19db4308 1183 (add-hook 'iswitchb-minibuffer-setup-hook
6b0cc1b5 1184 'iswitchb-init-XEmacs-trick))
962a4216 1185
36a3b01c 1186;;; XEmacs / backspace key
ccd2f997 1187;; For some reason, if the backspace key is pressed in XEmacs, the
962a4216 1188;; line gets confused, so I've added a simple key definition to make
19db4308 1189;; backspace act like the normal delete key.
962a4216
RS
1190
1191(defun iswitchb-xemacs-backspacekey ()
1192 "Bind backspace to `backward-delete-char'."
1193 (define-key iswitchb-mode-map '[backspace] 'backward-delete-char)
181688f2 1194 (define-key iswitchb-mode-map '[(meta backspace)] 'backward-kill-word))
962a4216 1195
2d839509 1196(if (featurep 'xemacs)
19db4308 1197 (add-hook 'iswitchb-define-mode-map-hook
962a4216
RS
1198 'iswitchb-xemacs-backspacekey))
1199
962a4216
RS
1200;;; ICOMPLETE TYPE CODE
1201
1202(defun iswitchb-exhibit ()
6c56c80b 1203 "Find matching buffers and display a list in the minibuffer.
962a4216
RS
1204Copied from `icomplete-exhibit' with two changes:
12051. It prints a default buffer name when there is no text yet entered.
12062. It calls my completion routine rather than the standard completion."
962a4216 1207 (if iswitchb-use-mycompletion
600f9d03 1208 (let ((contents (buffer-substring (minibuffer-prompt-end) (point-max)))
962a4216
RS
1209 (buffer-undo-list t))
1210 (save-excursion
1211 (goto-char (point-max))
1212 ; Register the end of input, so we
1213 ; know where the extra stuff
1214 ; (match-status info) begins:
1215 (if (not (boundp 'iswitchb-eoinput))
1216 ;; In case it got wiped out by major mode business:
1217 (make-local-variable 'iswitchb-eoinput))
1218 (setq iswitchb-eoinput (point))
1219 ;; Update the list of matches
1220 (setq iswitchb-text contents)
1221 (iswitchb-set-matches)
1222 (setq iswitchb-rescan t)
1223 (iswitchb-set-common-completion)
1224
1225 ;; Insert the match-status information:
f1180544 1226 (insert (iswitchb-completions
b21688f0 1227 contents))))))
26119624 1228
d7396512
JB
1229(defvar most-len)
1230(defvar most-is-exact)
c4ae2d51 1231
c80d9534
JW
1232(defun iswitchb-output-completion (com)
1233 (if (= (length com) most-len)
1234 ;; Most is one exact match,
1235 ;; note that and leave out
1236 ;; for later indication:
1237 (ignore
1238 (setq most-is-exact t))
1239 (substring com most-len)))
1240
b21688f0 1241(defun iswitchb-completions (name)
962a4216
RS
1242 "Return the string that is displayed after the user's text.
1243Modified from `icomplete-completions'."
f1180544 1244
962a4216
RS
1245 (let ((comps iswitchb-matches)
1246 ; "-determined" - only one candidate
b21688f0
EZ
1247 (open-bracket-determined "[")
1248 (close-bracket-determined "]")
962a4216
RS
1249 ;"-prospects" - more than one candidate
1250 (open-bracket-prospects "{")
1251 (close-bracket-prospects "}")
181688f2 1252 first)
962a4216 1253
b21688f0 1254 (if (and iswitchb-use-faces comps)
962a4216
RS
1255 (progn
1256 (setq first (car comps))
1257 (setq first (format "%s" first))
1258 (put-text-property 0 (length first) 'face
19db4308 1259 (if (= (length comps) 1)
b21688f0 1260 (if iswitchb-invalid-regexp
54907cdc
KS
1261 'iswitchb-invalid-regexp
1262 'iswitchb-single-match)
1263 'iswitchb-current-match)
19db4308 1264 first)
181688f2 1265 (setq comps (cons first (cdr comps)))))
962a4216 1266
c4ae2d51
JW
1267 ;; If no buffers matched, and virtual buffers are being used, then
1268 ;; consult the list of past visited files, to see if we can find
1269 ;; the file which the user might thought was still open.
1270 (when (and iswitchb-use-virtual-buffers (null comps)
e6d23bb5 1271 recentf-list)
c4ae2d51
JW
1272 (setq iswitchb-virtual-buffers nil)
1273 (let ((head recentf-list) name)
1274 (while head
1275 (if (and (setq name (file-name-nondirectory (car head)))
1276 (string-match (if iswitchb-regexp
1277 iswitchb-text
1278 (regexp-quote iswitchb-text)) name)
1279 (null (get-file-buffer (car head)))
1280 (not (assoc name iswitchb-virtual-buffers))
1281 (not (iswitchb-ignore-buffername-p name))
1282 (file-exists-p (car head)))
1283 (setq iswitchb-virtual-buffers
1284 (cons (cons name (car head))
1285 iswitchb-virtual-buffers)))
e6d23bb5
CY
1286 (setq head (cdr head)))
1287 (setq iswitchb-virtual-buffers (nreverse iswitchb-virtual-buffers)
1288 comps (mapcar 'car iswitchb-virtual-buffers))
c4ae2d51
JW
1289 (let ((comp comps))
1290 (while comp
1291 (put-text-property 0 (length (car comp))
54907cdc 1292 'face 'iswitchb-virtual-matches
c4ae2d51 1293 (car comp))
e6d23bb5 1294 (setq comp (cdr comp))))))
c4ae2d51 1295
962a4216
RS
1296 (cond ((null comps) (format " %sNo match%s"
1297 open-bracket-determined
1298 close-bracket-determined))
1299
b21688f0
EZ
1300 (iswitchb-invalid-regexp
1301 (concat " " (car comps)))
1302 ((null (cdr comps)) ;one match
1303 (concat
1304 (if (if (not iswitchb-regexp)
1305 (= (length name)
1306 (length (car comps)))
1307 (string-match name (car comps))
1308 (string-equal (match-string 0 (car comps))
1309 (car comps)))
1310 ""
1311 (concat open-bracket-determined
19db4308 1312 ;; when there is one match, show the
962a4216
RS
1313 ;; matching buffer name in full
1314 (car comps)
b21688f0
EZ
1315 close-bracket-determined))
1316 (if (not iswitchb-use-faces) " [Matched]")))
962a4216 1317 (t ;multiple matches
c80d9534
JW
1318 (if (and iswitchb-max-to-show
1319 (> (length comps) iswitchb-max-to-show))
1320 (setq comps
1321 (append
5f5d410a
JW
1322 (let ((res nil)
1323 (comp comps)
1324 (end (/ iswitchb-max-to-show 2)))
1325 (while (>= (setq end (1- end)) 0)
1326 (setq res (cons (car comp) res)
1327 comp (cdr comp)))
1328 (nreverse res))
c80d9534 1329 (list "...")
5f5d410a
JW
1330 (nthcdr (- (length comps)
1331 (/ iswitchb-max-to-show 2)) comps))))
962a4216
RS
1332 (let* (
1333 ;;(most (try-completion name candidates predicate))
1334 (most nil)
1335 (most-len (length most))
1336 most-is-exact
c4ae2d51
JW
1337 (alternatives
1338 (mapconcat (if most 'iswitchb-output-completion
6a0e4c60 1339 'identity) comps iswitchb-delim)))
962a4216
RS
1340
1341 (concat
1342
1343 ;; put in common completion item -- what you get by
1344 ;; pressing tab
4e141ed7
SE
1345 (if (and (stringp iswitchb-common-match-string)
1346 (> (length iswitchb-common-match-string) (length name)))
962a4216 1347 (concat open-bracket-determined
19db4308 1348 (substring iswitchb-common-match-string
962a4216 1349 (length name))
181688f2 1350 close-bracket-determined))
962a4216
RS
1351 ;; end of partial matches...
1352
1353 ;; think this bit can be ignored.
1354 (and (> most-len (length name))
1355 (concat open-bracket-determined
1356 (substring most (length name))
1357 close-bracket-determined))
f1180544 1358
962a4216
RS
1359 ;; list all alternatives
1360 open-bracket-prospects
1361 (if most-is-exact
6a0e4c60 1362 (concat iswitchb-delim alternatives)
962a4216 1363 alternatives)
181688f2 1364 close-bracket-prospects))))))
962a4216
RS
1365
1366(defun iswitchb-minibuffer-setup ()
6c56c80b
RS
1367 "Set up minibuffer for `iswitchb-buffer'.
1368Copied from `icomplete-minibuffer-setup-hook'."
8ae3ef6e
SM
1369 (when (iswitchb-entryfn-p)
1370 (set (make-local-variable 'iswitchb-use-mycompletion) t)
1371 (add-hook 'pre-command-hook 'iswitchb-pre-command nil t)
1372 (add-hook 'post-command-hook 'iswitchb-post-command nil t)
1373 (run-hooks 'iswitchb-minibuffer-setup-hook)))
962a4216
RS
1374
1375(defun iswitchb-pre-command ()
6c56c80b 1376 "Run before command in `iswitchb-buffer'."
962a4216
RS
1377 (iswitchb-tidy))
1378
962a4216 1379(defun iswitchb-post-command ()
6c56c80b 1380 "Run after command in `iswitchb-buffer'."
181688f2 1381 (iswitchb-exhibit))
962a4216
RS
1382
1383(defun iswitchb-tidy ()
1384 "Remove completions display, if any, prior to new user input.
1385Copied from `icomplete-tidy'."
1386
1387 (if (and (boundp 'iswitchb-eoinput)
1388 iswitchb-eoinput)
f1180544 1389
962a4216
RS
1390 (if (> iswitchb-eoinput (point-max))
1391 ;; Oops, got rug pulled out from under us - reinit:
1392 (setq iswitchb-eoinput (point-max))
1393 (let ((buffer-undo-list buffer-undo-list )) ; prevent entry
1394 (delete-region iswitchb-eoinput (point-max))))
f1180544 1395
962a4216
RS
1396 ;; Reestablish the local variable 'cause minibuffer-setup is weird:
1397 (make-local-variable 'iswitchb-eoinput)
1398 (setq iswitchb-eoinput 1)))
1399
962a4216 1400(defun iswitchb-entryfn-p ()
26119624 1401 "Return non-nil if we are using `iswitchb-buffer'."
c7b89861 1402 (eq iswitchb-minibuf-depth (minibuffer-depth)))
ccd2f997 1403
962a4216 1404(defun iswitchb-summaries-to-end ()
6c56c80b
RS
1405 "Move the summaries to the end of the list.
1406This is an example function which can be hooked on to
1407`iswitchb-make-buflist-hook'. Any buffer matching the regexps
1408`Summary' or `output\*$'are put to the end of the list."
19db4308
DL
1409 (let ((summaries (delq nil
1410 (mapcar
1411 (lambda (x)
1412 (if (string-match "Summary\\|output\\*$" x)
1413 x))
1414 iswitchb-temp-buflist))))
36a3b01c 1415 (iswitchb-to-end summaries)))
962a4216 1416
8097dd15 1417(defun iswitchb-case ()
4837b516 1418 "Return non-nil if we should ignore case when matching.
8097dd15
GM
1419See the variable `iswitchb-case' for details."
1420 (if iswitchb-case
2d839509 1421 (if (featurep 'xemacs)
8097dd15
GM
1422 (isearch-no-upper-case-p iswitchb-text)
1423 (isearch-no-upper-case-p iswitchb-text t))))
1424
19db4308 1425;;;###autoload
8ae3ef6e 1426(define-minor-mode iswitchb-mode
06e21633
CY
1427 "Toggle Iswitchb mode.
1428With a prefix argument ARG, enable Iswitchb mode if ARG is
1429positive, and disable it otherwise. If called from Lisp, enable
1430the mode if ARG is omitted or nil.
1431
1432Iswitchb mode is a global minor mode that enables switching
1433between buffers using substrings. See `iswitchb' for details."
8ae3ef6e 1434 nil nil iswitchb-global-map :global t :group 'iswitchb
19db4308
DL
1435 (if iswitchb-mode
1436 (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)
8ae3ef6e 1437 (remove-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)))
19db4308 1438
962a4216
RS
1439(provide 'iswitchb)
1440
6c56c80b 1441;;; iswitchb.el ends here