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