comparison lisp/packages/iswitchb.el @ 195:a2f645c6b9f8 r20-3b24

Import from CVS: tag r20-3b24
author cvs
date Mon, 13 Aug 2007 09:59:05 +0200
parents
children 850242ba4a81
comparison
equal deleted inserted replaced
194:2947057885e5 195:a2f645c6b9f8
1 ;;; iswitchb.el --- switch between buffers using substrings
2
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
4
5 ;; Author: Stephen Eglen <stephen@cns.ed.ac.uk>
6 ;; Maintainer: Stephen Eglen <stephen@cns.ed.ac.uk>
7 ;; Keywords: extensions
8 ;; location: http://www.cogs.susx.ac.uk/users/stephene/emacs
9 ;; RCS: $Id: iswitchb.el,v 1.1 1997/09/27 16:57:40 steve Exp $
10
11 ;; This file is part of GNU Emacs.
12
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
17
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
27
28 ;;; Installation:
29
30 ;; To get the functions in this package bound to keys, do
31 ;; (iswitchb-default-keybindings)
32
33 ;;; Commentary:
34
35 ;; As you type in a substring, the list of buffers currently matching
36 ;; the substring are displayed as you type. The list is ordered so
37 ;; that the most recent buffers visited come at the start of the list.
38 ;; The buffer at the start of the list will be the one visited when
39 ;; you press return. By typing more of the substring, the list is
40 ;; narrowed down so that gradually the buffer you want will be at the
41 ;; top of the list. Alternatively, you can use C-s an C-r to rotate
42 ;; buffer names in the list until the one you want is at the top of
43 ;; the list. Completion is also available so that you can see what is
44 ;; common to all of the matching buffers as you type.
45
46 ;; This code is similar to a couple of other packages. Michael R Cook
47 ;; <mcook@cognex.com wrote a similar buffer switching package, but
48 ;; does exact matching rather than substring matching on buffer names.
49 ;; I also modified a couple of functions from icomplete.el to provide
50 ;; the completion feedback in the minibuffer.
51
52 ;;; Example
53
54 ;;If I have two buffers called "123456" and "123", with "123456" the
55 ;;most recent, when I use iswitchb, I first of all get presented with
56 ;;the list of all the buffers
57 ;;
58 ;; iswitch {123456,123}
59 ;;
60 ;; If I then press 2:
61 ;; iswitch 2[3]{123456,123}
62 ;;
63 ;; The list in {} are the matching buffers, most recent first (buffers
64 ;; visible in the current frame are put at the end of the list by
65 ;; default). At any time I can select the item at the head of the
66 ;; list by pressing RET. I can also bring the put the first element
67 ;; at the end of the list by pressing C-s, or put the last element at
68 ;; the head of the list by pressing C-r. The item in [] indicates
69 ;; what can be added to my input by pressing TAB. In this case, I
70 ;; will get "3" added to my input. So, press TAB:
71 ;; iswitch 23{123456,123}
72 ;;
73 ;; At this point, I still have two matching buffers.
74 ;; If I want the first buffer in the list, I simply press RET. If I
75 ;; wanted the second in the list, I could press C-s to move it to the
76 ;; top of the list and then RET to select it.
77 ;;
78 ;;However, If I type 4, I only have one match left:
79 ;; iswitch 234[123456] [Matched]
80 ;;
81 ;;Since there is only one matching buffer left, it is given in [] and we
82 ;;see the text [Matched] afterwards. I can now press TAB or RET to go
83 ;;to that buffer.
84 ;;
85 ;; If however, I now type "a":
86 ;; iswitch 234a [No match]
87 ;; There are no matching buffers. If I press RET or TAB, I can be
88 ;; prompted to create a new buffer called "234a".
89 ;;
90 ;; Of course, where this function comes in really useful is when you
91 ;; can specify the buffer using only a few keystrokes. In the above
92 ;; example, the quickest way to get to the "123456" buffer would be
93 ;; just to type 4 and then RET (assuming there isnt any newer buffer
94 ;; with 4 in its name).
95
96 ;; To see a full list of all matching buffers in a separate buffer,
97 ;; hit ? or press TAB when there are no further completions to the
98 ;; substring.
99
100 ;; The buffer at the head of the list can be killed by pressing C-k.
101 ;; If the buffer needs saving, you will be queried before the buffer
102 ;; is killed.
103
104 ;; If you find that the file you are after is not in a buffer, you can
105 ;; press C-x C-f to immediately drop into find-file.
106
107 ;;
108 ;; See the doc string of iswitchb for full keybindings and features.
109 ;; (describe-function 'iswitchb)
110
111 ;;; Customisation
112
113 ;; See the User Variables section below for easy ways to change the
114 ;; functionality of the program. These are accessible using the
115 ;; custom package.
116 ;; To modify the keybindings, use the hook provided. For example:
117 ;;(add-hook 'iswitchb-define-mode-map-hook
118 ;; 'iswitchb-my-keys)
119 ;;
120 ;;(defun iswitchb-my-keys ()
121 ;; "Add my keybings for iswitchb."
122 ;; (define-key iswitchb-mode-map " " 'iswitchb-next-match)
123 ;; )
124 ;;
125 ;; Seeing all the matching buffers.
126 ;;
127 ;; If you have many matching buffers, they may not all fit onto one
128 ;; line of the minibuffer. In this case, you should use rsz-mini
129 ;; (resize-minibuffer-mode). You can also limit iswitchb so that it
130 ;; only shows a certain number of lines -- see the documentation for
131 ;; `iswitchb-minibuffer-setup-hook'.
132
133
134 ;; Changing the list of buffers.
135
136 ;; By default, the list of current buffers is most recent first,
137 ;; oldest last, with the exception that the buffers visible in the
138 ;; current frame are put at the end of the list. A hook exists to
139 ;; allow other functions to order the list. For example, if you add:
140 ;;
141 ;; (add-hook 'iswitchb-make-buflist-hook 'iswitchb-summaries-to-end)
142 ;;
143 ;; then all buffers matching "Summary" are moved to the end of the
144 ;; list. (I find this handy for keeping the INBOX Summary and so on
145 ;; out of the way.) It also moves buffers matching "output\*$" to the
146 ;; end of the list (these are created by AUC TeX when compiling.)
147 ;; Other functions could be made available which alter the list of
148 ;; matching buffers (either deleting or rearranging elements.)
149
150 ;; Font-Lock
151
152 ;; If you have font-lock loaded, the first matching buffer is
153 ;; highlighted. To switch this off, set (setq iswitchb-use-fonts nil)
154 ;; I don't use font-lock that much, so I've hardcoded the faces. If
155 ;; this is too harsh, let me know. Colouring of the matching buffer
156 ;; name was suggested by Carsten Dominik (dominik@strw.leidenuniv.nl)
157
158 ;;; Comparison with iswitch-buffer
159
160 ;; This package is a rewrite of iswitch-buffer, using the minibuffer
161 ;; rather than the echo area. The advantages of using the minibuffer
162 ;; are several:
163 ;; o minibuffer has more powerful editing facilities
164 ;; o doesnt interfere with other packages that use the echo area
165 ;; o *Messages* buffer doesnt get filled up with all of the messages that
166 ;; go to the modeline
167 ;; o cursor is in the minibuffer, which somehow looks right.
168 ;; o minibuffer can be resized dynamically to show all the possible matching
169 ;; buffers rather than just the first line's worth (using rsz-mini).
170 ;;
171 ;; Disadvantages:
172 ;; o cant change the prompt to indicate status of searching (eg whether
173 ;; regexp searching is currently on).
174
175
176 ;;; TODO
177 ;; Could this selection also be used for other buffer selection
178 ;; routines, such as append-to-buffer and kill-buffer?
179
180 ;; Pressing Tab key twice (without completion) does not scroll the
181 ;; list of buffers.
182
183 ;;; Acknowledgements
184
185 ;; Thanks to Jari Aalto <jari.aalto@poboxes.com> for help with the
186 ;; first version of this package, iswitch-buffer. Thanks also to many
187 ;; others for testing earlier versions.
188
189 ;;; Code:
190
191 ;; Set up the custom library.
192 ;; taken from http://www.dina.kvl.dk/~abraham/custom/
193 (eval-and-compile
194 (condition-case ()
195 (require 'custom)
196 (error nil))
197 (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
198 nil ;; We've got what we needed
199 ;; We have the old custom-library, hack around it!
200 (defmacro defgroup (&rest args)
201 nil)
202 (defmacro defcustom (var value doc &rest args)
203 (` (defvar (, var) (, value) (, doc))))))
204
205 ;;; User Variables
206 ;;
207 ;; These are some things you might want to change.
208
209 (defgroup iswitchb nil
210 "switch between buffers using substrings."
211 :group 'extensions
212 ;; These links are to be added in later versions of custom and
213 ;; so are currently commented out.
214 :link '(emacs-commentary-link :tag "Commentary" "iswitchb.el")
215 :link '(emacs-library-link :tag "Lisp File" "iswitchb.el")
216 )
217
218
219 (defcustom iswitchb-case case-fold-search
220 "*Non-nil if searching of buffer names should ignore case."
221 :type 'boolean
222 :group 'iswitchb)
223
224 (defcustom iswitchb-buffer-ignore
225 '("^ ")
226 "*List of regexps or functions matching buffer names to ignore.
227 For example, traditional behavior is not to list buffers whose names begin
228 with a space, for which the regexp is `^ '. See the source file for
229 example functions that filter buffernames."
230 :type '(repeat regexp)
231 :group 'iswitchb)
232
233
234 ;;; Examples for setting the value of iswitchb-buffer-ignore
235 ;(defun -c-mode (name)
236 ; "Ignore all c mode buffers -- example function for iswitchb."
237 ; (save-excursion
238 ; (set-buffer name)
239 ; (string-match "^C$" mode-name)))
240
241 ;(setq iswitchb-buffer-ignore '("^ " ignore-c-mode))
242 ;(setq iswitchb-buffer-ignore '("^ " "\\.c$" "\\.h$"))
243
244 (defcustom iswitchb-default-method 'always-frame
245 "*How to switch to new buffer when using `iswitchb-buffer'.
246 Possible values:
247 `samewindow' Show new buffer in same window
248 `otherwindow' Show new buffer in another window (same frame)
249 `display' Display buffer in another window without switching to it
250 `otherframe' Show new buffer in another frame
251 `maybe-frame' If a buffer is visible in another frame, prompt to ask if you
252 you want to see the buffer in the same window of the current
253 frame or in the other frame.
254 `always-frame' If a buffer is visible in another frame, raise that
255 frame. Otherwise, visit the buffer in the same window."
256 :type '(choice (const :tag "samewindow" samewindow)
257 (const :tag "otherwindow" otherwindow)
258 (const :tag "display" display)
259 (const :tag "otherframe" otherframe)
260 (const :tag "maybe-frame" maybe-frame)
261 (const :tag "always-frame" always-frame))
262 :group 'iswitchb)
263
264
265 (defcustom iswitchb-regexp nil
266 "*Non-nil means that `iswitchb' will do regexp matching.
267 Value can be toggled within `iswitchb'."
268 :type 'boolean
269 :group 'iswitchb)
270
271
272 (defcustom iswitchb-newbuffer t
273 "*Non-nil means create new buffer if no buffer matches substring.
274 See also `iswitchb-prompt-newbuffer'."
275 :type 'boolean
276 :group 'iswitchb)
277
278
279 (defcustom iswitchb-prompt-newbuffer t
280 "*Non-nil means prompt user to confirm before creating new buffer.
281 See also `iswitchb-newbuffer'."
282 :type 'boolean
283 :group 'iswitchb)
284
285
286 (defcustom iswitchb-define-mode-map-hook nil
287 "*Hook to define keys in `iswitchb-mode-map' for extra keybindings."
288 :type 'hook
289 :group 'iswitchb)
290
291
292
293 (defcustom iswitchb-use-fonts t
294 "*Non-nil means use fonts for showing first match."
295 :type 'boolean
296 :group 'iswitchb)
297
298
299 (defcustom iswitchb-make-buflist-hook nil
300 "*Hook to run when list of matching buffers is created."
301 :type 'hook
302 :group 'iswitchb)
303
304
305
306 (defvar iswitchb-method nil
307 "*Stores the method for viewing the selected buffer.
308 Its value is one of `samewindow', `otherwindow', `display', `otherframe',
309 `maybe-frame' or `always-frame'. See `iswitchb-default-method' for
310 details of values.")
311
312 (defvar iswitchb-all-frames 'visible
313 "*Argument to pass to `walk-windows' when finding visible buffers.
314 See documentation of `walk-windows' for useful values.")
315
316
317
318 ;; Do we need the variable iswitchb-use-mycompletion?
319
320
321 ;;; Internal Variables
322 (defvar iswitchb-minibuffer-setup-hook nil
323 "Iswitchb-specific customization of minibuffer setup.
324
325 This hook is run during minibuffer setup iff `iswitchb' will be active.
326 It is intended for use in customizing iswitchb for interoperation
327 with other packages. For instance:
328
329 \(add-hook 'iswitchb-minibuffer-setup-hook
330 \(function
331 \(lambda ()
332 \(make-local-variable 'resize-minibuffer-window-max-height)
333 \(setq resize-minibuffer-window-max-height 3))))
334
335 will constrain rsz-mini to a maximum minibuffer height of 3 lines when
336 iswitchb is running. Copied from `icomplete-minibuffer-setup-hook'.")
337
338 (defvar iswitchb-eoinput 1
339 "Point where minibuffer input ends and completion info begins.
340 Copied from `icomplete-eoinput'.")
341 (make-variable-buffer-local 'iswitchb-eoinput)
342
343
344 (defvar iswitchb-buflist nil
345 "Stores the current list of buffers that will be searched through.
346 The list is ordered, so that the most recent buffers come first,
347 although by default, the buffers visible in the current frame are put
348 at the end of the list. Created by `iswitchb-make-buflist'.")
349
350 ;; todo -- is this necessary?
351
352 (defvar iswitchb-use-mycompletion nil
353 "Non-nil means use `iswitchb-buffer' completion feedback.
354 Should only be set to t by iswitchb functions, so that it doesn't
355 interfere with other minibuffer usage.")
356
357 (defvar iswitchb-change-word-sub nil
358 "Private variable used by `iswitchb-word-matching-substring'.")
359
360
361 (defvar iswitchb-common-match-string nil
362 "Stores the string that is common to all matching buffers.")
363
364
365 (defvar iswitchb-rescan nil
366 "Non-nil means we need to regenerate the list of matching buffers.")
367
368 (defvar iswitchb-text nil
369 "Stores the users string as it is typed in.")
370
371 (defvar iswitchb-matches nil
372 "List of buffers currenly matching `iswitchb-text'.")
373
374 (defvar iswitchb-mode-map nil
375 "Keymap for `iswitchb-buffer'.")
376
377 (defvar iswitchb-history nil
378 "History of buffers selected using `iswitchb-buffer'.")
379
380 (defvar iswitchb-exit nil
381 "Flag to monitor how `iswitchb-buffer' exits.
382 If equal to `takeprompt', we use the prompt as the buffer name to be
383 selected.")
384
385 (defvar iswitchb-buffer-ignore-orig nil
386 "Stores original value of `iswitchb-buffer-ignore'.")
387
388 (defvar iswitchb-xemacs (string-match "XEmacs" (emacs-version))
389 "Non-nil if we are running XEmacs. Otherwise, assume we are running Emacs.")
390
391
392 ;;; FUNCTIONS
393
394
395 ;;; ISWITCHB KEYMAP
396 (defun iswitchb-define-mode-map ()
397 "Set up the keymap for `iswitchb-buffer'."
398 (interactive)
399 (let (map)
400 ;; generated every time so that it can inheret new functions.
401 ;;(or iswitchb-mode-map
402
403 (setq map (copy-keymap minibuffer-local-map))
404 (define-key map "?" 'iswitchb-completion-help)
405 (define-key map "\C-s" 'iswitchb-next-match)
406 (define-key map "\C-r" 'iswitchb-prev-match)
407 (define-key map "\t" 'iswitchb-complete)
408 (define-key map "\C-j" 'iswitchb-select-buffer-text)
409 (define-key map "\C-t" 'iswitchb-toggle-regexp)
410 (define-key map "\C-x\C-f" 'iswitchb-find-file)
411 ;;(define-key map "\C-a" 'iswitchb-toggle-ignore)
412 (define-key map "\C-c" 'iswitchb-toggle-case)
413 (define-key map "\C-k" 'iswitchb-kill-buffer)
414 (setq iswitchb-mode-map map)
415 (run-hooks 'iswitchb-define-mode-map-hook)
416 ))
417
418
419
420 ;;; MAIN FUNCTION
421 (defun iswitchb ()
422 "Switch to buffer matching a substring.
423 As you type in a string, all of the buffers matching the string are
424 displayed. When you have found the buffer you want, it can then be
425 selected. As you type, most keys have their normal keybindings,
426 except for the following:
427 \\<iswitchb-mode-map>
428
429 RET Select the buffer at the front of the list of matches. If the
430 list is empty, possibly prompt to create new buffer.
431
432 \\[iswitchb-select-buffer-text] Select the current prompt as the buffer.
433 If no buffer is found, prompt for a new one.
434
435 \\[iswitchb-next-match] Put the first element at the end of the list.
436 \\[iswitchb-prev-match] Put the last element at the start of the list.
437 \\[iswitchb-complete] Complete a common suffix to the current string that
438 matches all buffers. If there is only one match, select that buffer.
439 If there is no common suffix, show a list of all matching buffers
440 in a separate window.
441 \\[iswitchb-toggle-regexp] Toggle rexep searching.
442 \\[iswitchb-toggle-case] Toggle case-sensitive searching of buffer names.
443 \\[iswitchb-completion-help] Show list of matching buffers in separate window.
444 \\[iswitchb-find-file] Exit iswitchb and drop into find-file.
445 \\[iswitchb-kill-buffer] Kill buffer at head of buffer list."
446 ;;\\[iswitchb-toggle-ignore] Toggle ignoring certain buffers (see \
447 ;;`iswitchb-buffer-ignore')
448
449 (let
450 (
451 prompt
452 buf-sel
453 iswitchb-final-text
454 (minibuffer-confirm-incomplete nil) ;XEmacs todo: prevent `;confirm'
455 (icomplete-mode nil) ;; prevent icomplete starting up
456 ;; can only use fonts if they have been bound.
457 (iswitchb-use-fonts (and iswitchb-use-fonts
458 (boundp 'font-lock-comment-face)
459 (boundp 'font-lock-function-name-face)))
460 )
461
462 (iswitchb-define-mode-map)
463 (setq iswitchb-exit nil)
464 (setq iswitchb-rescan t)
465 (setq iswitchb-text "")
466 (iswitchb-set-matches)
467 (setq prompt (format "iswitch "))
468 (iswitchb-make-buflist)
469 (let
470 ((minibuffer-local-completion-map iswitchb-mode-map))
471 ;; prompt the user for the buffer name
472 (setq iswitchb-final-text (completing-read prompt
473 ;;nil
474 '(("dummy".1))
475 ;;("2".2) ("3".3))
476 nil nil
477 nil;init string
478 'iswitchb-history)))
479
480 ;;(message "chosen text %s" iswitchb-final-text)
481 ;; Choose the buffer name: either the text typed in, or the head
482 ;; of the list of matches
483
484 (cond ( (eq iswitchb-exit 'findfile)
485 (call-interactively 'find-file))
486
487 (t
488 (if (or
489 (eq iswitchb-exit 'takeprompt)
490 (null iswitchb-matches))
491 (setq buf-sel iswitchb-final-text)
492 ;; else take head of list
493 (setq buf-sel (car iswitchb-matches)))
494
495 ;; Or possibly choose the default buffer
496 (if (equal iswitchb-final-text "")
497 (setq buf-sel (car iswitchb-matches)))
498
499 ;; View the buffer
500 (message "go to buf %s" buf-sel)
501 ;; Check buf-sel is non-nil.
502 (if buf-sel
503 (if (get-buffer buf-sel)
504 ;; buffer exists, so view it and then exit
505 (iswitchb-visit-buffer buf-sel)
506 ;; else buffer doesnt exist
507 (iswitchb-possible-new-buffer buf-sel)))
508 ))
509
510 ))
511
512
513 ;;; COMPLETION CODE
514
515 (defun iswitchb-set-common-completion ()
516 "Find common completion of `iswitchb-text' in `iswitchb-matches'.
517 The result is stored in `iswitchb-common-match-string'."
518
519 (let* (val)
520 (setq iswitchb-common-match-string nil)
521 (if (and iswitchb-matches
522 (stringp iswitchb-text)
523 (> (length iswitchb-text) 0))
524 (if (setq val (iswitchb-find-common-substring
525 iswitchb-matches iswitchb-text))
526 (setq iswitchb-common-match-string val)))
527 val
528 ))
529
530
531 (defun iswitchb-complete ()
532 "Try and complete the current pattern amongst the buffer names."
533 (interactive)
534 (let (res)
535 (cond ((not iswitchb-matches)
536 (iswitchb-completion-help)
537 )
538
539 ((eq 1 (length iswitchb-matches))
540 ;; only one choice, so select it.
541 (exit-minibuffer))
542
543 (t
544 ;; else there could be some completions
545
546 (setq res (iswitchb-find-common-substring
547 iswitchb-matches iswitchb-text))
548 (if (and (not (memq res '(t nil)))
549 (not (equal res iswitchb-text)))
550 ;; found something to complete, so put it in the minibuff.
551 (progn
552 (setq iswitchb-rescan nil)
553 (delete-region (point-min) (point))
554 (insert res))
555 ;; else nothing to complete
556 (iswitchb-completion-help)
557 )
558 )
559 )))
560
561
562
563 ;;; TOGGLE FUNCTIONS
564
565 (defun iswitchb-toggle-case ()
566 "Toggle the value of `iswitchb-case'."
567 (interactive)
568 (setq iswitchb-case (not iswitchb-case))
569 ;; ask for list to be regenerated.
570 (setq iswitchb-rescan t)
571 )
572
573 (defun iswitchb-toggle-regexp ()
574 "Toggle the value of `iswitchb-regexp'."
575 (interactive)
576 (setq iswitchb-regexp (not iswitchb-regexp))
577 ;; ask for list to be regenerated.
578 (setq iswitchb-rescan t)
579 )
580
581
582 (defun iswitchb-toggle-ignore ()
583 "Toggle ignoring buffers specified with `iswitchb-buffer-ignore'."
584 (interactive)
585 (if iswitchb-buffer-ignore
586 (progn
587 (setq iswitchb-buffer-ignore-orig iswitchb-buffer-ignore)
588 (setq iswitchb-buffer-ignore nil)
589 )
590 ;; else
591 (setq iswitchb-buffer-ignore iswitchb-buffer-ignore-orig)
592 )
593 ;; ask for list to be regenerated.
594 (setq iswitchb-rescan t)
595 )
596
597
598 (defun iswitchb-select-buffer-text ()
599 "Select the buffer named by the prompt.
600 If no buffer exactly matching the prompt exists, maybe create a new one."
601 (interactive)
602 (setq iswitchb-exit 'takeprompt)
603 (exit-minibuffer))
604
605
606
607 (defun iswitchb-find-file ()
608 "Drop into find-file from buffer switching."
609 (interactive)
610 (setq iswitchb-exit 'findfile)
611 (exit-minibuffer))
612
613 (defun iswitchb-next-match ()
614 "Put first element of `iswitchb-matches' at the end of the list."
615 (interactive)
616 (let ((next (cadr iswitchb-matches)))
617 (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist next))
618 (setq iswitchb-rescan t)
619 ))
620
621 (defun iswitchb-prev-match ()
622 "Put last element of `iswitchb-matches' at the front of the list."
623 (interactive)
624 (let ((prev (car (last iswitchb-matches))))
625 (setq iswitchb-buflist (iswitchb-chop iswitchb-buflist prev))
626 (setq iswitchb-rescan t)
627 ))
628
629
630
631
632 (defun iswitchb-chop (list elem)
633 "Remove all elements before ELEM and put them at the end of LIST."
634 (let ((ret nil)
635 (next nil)
636 (sofar nil))
637 (while (not ret)
638 (setq next (car list))
639 (if (equal next elem)
640 (setq ret (append list (nreverse sofar)))
641 ;; else
642 (progn
643 (setq list (cdr list))
644 (setq sofar (cons next sofar)))))
645 ret))
646
647
648
649
650 ;;; CREATE LIST OF ALL CURRENT BUFFERS
651
652
653 (defun iswitchb-make-buflist ()
654 "Set `iswitchb-buflist' to the current list of buffers.
655 Currently visible buffers are put at the end of the list.
656 The hook `iswitchb-make-buflist-hook' is run after the list has been
657 created to allow the user to further modify the order of the buffer names
658 in this list."
659 (setq iswitchb-buflist
660 (let* ((iswitchb-current-buffers (iswitchb-get-buffers-in-frames))
661 (buflist
662 (delq nil
663 (mapcar
664 (lambda (x)
665 (let ((b-name (buffer-name x)))
666 (if (not
667 (or
668 (iswitchb-ignore-buffername-p b-name)
669 (memq b-name iswitchb-current-buffers)))
670 b-name)))
671 (buffer-list)))))
672 (nconc buflist iswitchb-current-buffers)
673 (run-hooks 'iswitchb-make-buflist-hook)
674 buflist)))
675
676 (defun iswitchb-to-end (lst)
677 "Move the elements from LST to the end of BUFLIST."
678 (mapcar
679 (lambda (elem)
680 (setq buflist (delq elem buflist)))
681 lst)
682 (nconc buflist lst))
683
684
685
686 (defun iswitchb-get-buffers-in-frames (&optional current)
687 "Return the list of buffers that are visible in the current frame.
688 If optional argument `current' is given, restrict searching to the
689 current frame, rather than all frames, regardless of value of
690 `iswitchb-all-frames'."
691 (let ((iswitchb-bufs-in-frame nil))
692 (walk-windows 'iswitchb-get-bufname nil
693 (if current
694 nil
695 iswitchb-all-frames))
696 iswitchb-bufs-in-frame))
697
698
699 (defun iswitchb-get-bufname (win)
700 "Used by `iswitchb-get-buffers-in-frames' to walk through all windows."
701 (let ((buf (buffer-name (window-buffer win))))
702 (if (not (member buf iswitchb-bufs-in-frame))
703 ;; Only add buf if it is not already in list.
704 ;; This prevents same buf in two different windows being
705 ;; put into the list twice.
706 (setq iswitchb-bufs-in-frame
707 (cons buf iswitchb-bufs-in-frame)))))
708
709
710 ;;; FIND MATCHING BUFFERS
711
712
713 (defun iswitchb-set-matches ()
714 "Set `iswitchb-matches' to the list of buffers matching prompt."
715 (if iswitchb-rescan
716 (setq iswitchb-matches
717 (let* ((buflist iswitchb-buflist)
718 )
719 (iswitchb-get-matched-buffers iswitchb-text iswitchb-regexp
720 buflist)))))
721
722 (defun iswitchb-get-matched-buffers (regexp
723 &optional string-format buffer-list)
724 "Return buffers matching REGEXP.
725 If STRING-FORMAT is non-nil, consider REGEXP as string.
726 BUFFER-LIST can be list of buffers or list of strings."
727 (let* ((case-fold-search iswitchb-case)
728 ;; need reverse since we are building up list backwards
729 (list (reverse buffer-list))
730 (do-string (stringp (car list)))
731 name
732 ret
733 )
734 (mapcar
735 (lambda (x)
736
737 (if do-string
738 (setq name x) ;We already have the name
739 (setq name (buffer-name x)))
740
741 (cond
742 ((and (or (and string-format (string-match regexp name))
743 (and (null string-format)
744 (string-match (regexp-quote regexp) name)))
745
746 ;; todo (not (iswitchb-ignore-buffername-p name))
747 )
748 (setq ret (cons name ret))
749 )))
750 list)
751 ret
752 ))
753
754
755
756
757 (defun iswitchb-ignore-buffername-p (bufname)
758 "Return t if the buffer BUFNAME should be ignored."
759 (let ((data (match-data))
760 (re-list iswitchb-buffer-ignore)
761 ignorep
762 nextstr
763 )
764 (while re-list
765 (setq nextstr (car re-list))
766 (cond
767 ((stringp nextstr)
768 (if (string-match nextstr bufname)
769 (progn
770 (setq ignorep t)
771 (setq re-list nil))))
772 ((fboundp nextstr)
773 (if (funcall nextstr bufname)
774 (progn
775 (setq ignorep t)
776 (setq re-list nil))
777 ))
778 )
779 (setq re-list (cdr re-list)))
780 (store-match-data data)
781
782 ;; return the result
783 ignorep)
784 )
785
786
787
788 (defun iswitchb-word-matching-substring (word)
789 "Return part of WORD before 1st match to `iswitchb-change-word-sub'.
790 If `iswitchb-change-word-sub' cannot be found in WORD, return nil."
791 (let ((case-fold-search iswitchb-case))
792 (let ((m (string-match iswitchb-change-word-sub word)))
793 (if m
794 (substring word m)
795 ;; else no match
796 nil))))
797
798
799
800
801
802
803 (defun iswitchb-find-common-substring (lis subs)
804 "Return common string following SUBS in each element of LIS."
805 (let (res
806 alist
807 iswitchb-change-word-sub
808 )
809 (setq iswitchb-change-word-sub
810 (if iswitchb-regexp
811 subs
812 (regexp-quote subs)))
813 (setq res (mapcar 'iswitchb-word-matching-substring lis))
814 (setq res (delq nil res)) ;; remove any nil elements (shouldnt happen)
815 (setq alist (mapcar 'iswitchb-makealist res)) ;; could use an OBARRAY
816
817 ;; try-completion returns t if there is an exact match.
818 (let ((completion-ignore-case iswitchb-case))
819
820 (try-completion subs alist)
821 )))
822
823
824 (defun iswitchb-makealist (res)
825 "Return dotted pair (RES . 1)."
826 (cons res 1))
827
828 ;; from Wayne Mesard <wmesard@esd.sgi.com>
829 (defun iswitchb-rotate-list (lis)
830 "Destructively removes the last element from LIS.
831 Return the modified list with the last element prepended to it."
832 (if (<= (length lis) 1)
833 lis
834 (let ((las lis)
835 (prev lis))
836 (while (consp (cdr las))
837 (setq prev las
838 las (cdr las)))
839 (setcdr prev nil)
840 (cons (car las) lis))
841 ))
842
843
844 (defun iswitchb-completion-help ()
845 "Show possible completions in a *Buffer Completions* buffer."
846 ;; we could allow this buffer to be used to select match, but I think
847 ;; choose-completion-string will need redefining, so it just inserts
848 ;; choice with out any previous input.
849 (interactive)
850 (setq iswitchb-rescan nil)
851 (let ((completion-setup-hook nil) ;disable fancy highlight/selection.
852 )
853 (with-output-to-temp-buffer "*Buffer Completions*"
854 (if iswitchb-xemacs
855
856 ;; XEmacs extents are put on by default, doesn't seem to be
857 ;; any way of switching them off.
858 (display-completion-list (if iswitchb-matches
859 iswitchb-matches
860 iswitchb-buflist)
861 :help-string "iswitchb "
862 :activate-callback
863 '(lambda (x y z)
864 (message "doesnt work yet, sorry!")))
865 ;; else running Emacs
866 (display-completion-list (if iswitchb-matches
867 iswitchb-matches
868 iswitchb-buflist))
869 ))))
870
871
872 ;;; KILL CURRENT BUFFER
873
874 (defun iswitchb-kill-buffer ()
875 "Kill the buffer at the head of `iswtichb-matches'."
876 (interactive)
877 (let ( (enable-recursive-minibuffers t)
878 buf)
879
880 (setq buf (car iswitchb-matches))
881 ;; check to see if buf is non-nil.
882 (if buf
883 (progn
884 (kill-buffer buf)
885
886 ;; Check if buffer exists. XEmacs gnuserv.el makes alias
887 ;; for kill-buffer which does not return t if buffer is
888 ;; killed, so we can't rely on kill-buffer return value.
889 (if (get-buffer buf)
890 ;; buffer couldn't be killed.
891 (setq iswitchb-rescan t)
892 ;; else buffer was killed so remove name from list.
893 (setq iswitchb-buflist (delq buf iswitchb-buflist)))))))
894
895
896 ;;; VISIT CHOSEN BUFFER
897 (defun iswitchb-visit-buffer (buffer)
898 "Visit buffer named BUFFER according to `iswitchb-method'."
899 (let* (win newframe)
900 (cond
901 ((eq iswitchb-method 'samewindow)
902 (switch-to-buffer buffer))
903
904 ((memq iswitchb-method '(always-frame maybe-frame))
905 (cond
906 ((and (setq win (iswitchb-window-buffer-p buffer))
907 (or (eq iswitchb-method 'always-frame)
908 (y-or-n-p "Jump to frame? ")))
909 (setq newframe (window-frame win))
910 (raise-frame newframe)
911 (select-frame newframe)
912 (select-window win)
913 (if (not iswitchb-xemacs)
914 ;; reposition mouse to make frame active. not needed in XEmacs
915 ;; This line came from the other-frame defun in Emacs.
916 (set-mouse-position (selected-frame) (1- (frame-width)) 0))
917 )
918 (t
919 ;; No buffer in other frames...
920 (switch-to-buffer buffer)
921 )))
922
923
924
925 ((eq iswitchb-method 'otherwindow)
926 (switch-to-buffer-other-window buffer))
927
928 ((eq iswitchb-method 'display)
929 (display-buffer buffer))
930
931 ((eq iswitchb-method 'otherframe)
932 (progn
933 (switch-to-buffer-other-frame buffer)
934 (if (not iswitchb-xemacs)
935 (set-mouse-position (selected-frame) (1- (frame-width)) 0))
936 )
937 ) )))
938
939 (defun iswitchb-possible-new-buffer (buf)
940 "Possibly create and visit a new buffer called BUF."
941
942 (let ((newbufcreated))
943 (if (and iswitchb-newbuffer
944 (or
945 (not iswitchb-prompt-newbuffer)
946
947 (and iswitchb-prompt-newbuffer
948 (y-or-n-p
949 (format
950 "No buffer matching `%s', create one? "
951 buf)))))
952 ;; then create a new buffer
953 (progn
954 (setq newbufcreated (get-buffer-create buf))
955 (if (fboundp 'set-buffer-major-mode)
956 (set-buffer-major-mode newbufcreated))
957 (iswitchb-visit-buffer newbufcreated))
958
959 ;; else wont create new buffer
960 (message (format "no buffer matching `%s'" buf))
961 )))
962
963 (defun iswitchb-window-buffer-p (buffer)
964 "Return window pointer if BUFFER is visible in another frame.
965 If BUFFER is visible in the current frame, return nil."
966 (interactive)
967 (let ((blist (iswitchb-get-buffers-in-frames 'current)))
968 ;;If the buffer is visible in current frame, return nil
969 (if (memq buffer blist)
970 nil
971 ;; maybe in other frame...
972 (get-buffer-window buffer 'visible)
973 )))
974
975 ;;;###autoload
976 (defun iswitchb-default-keybindings ()
977 "Set up default keybindings for `iswitchb-buffer'.
978 Call this function to override the normal bindings."
979 (interactive)
980 (global-set-key (read-kbd-macro "C-x b") 'iswitchb-buffer)
981 (global-set-key (read-kbd-macro "C-x 4 b") 'iswitchb-buffer-other-window)
982 (global-set-key (read-kbd-macro "C-x 4 C-o") 'iswitchb-display-buffer)
983 (global-set-key (read-kbd-macro "C-x 5 b") 'iswitchb-buffer-other-frame))
984
985
986
987 ;;;###autoload
988 (defun iswitchb-buffer ()
989 "Switch to another buffer.
990
991 The buffer name is selected interactively by typing a substring. The
992 buffer is displayed according to `iswitchb-default-method' -- the
993 default is to show it in the same window, unless it is already visible
994 in another frame.
995 For details of keybindings, do `\\[describe-function] iswitchb'."
996 (interactive)
997 (setq iswitchb-method iswitchb-default-method)
998 (iswitchb-entry))
999
1000
1001 ;;;###autoload
1002 (defun iswitchb-buffer-other-window ()
1003 "Switch to another buffer and show it in another window.
1004 The buffer name is selected interactively by typing a substring.
1005 For details of keybindings, do `\\[describe-function] iswitchb'."
1006 (interactive)
1007 (setq iswitchb-method 'otherwindow)
1008 (iswitchb-entry))
1009
1010
1011
1012 ;;;###autoload
1013 (defun iswitchb-display-buffer ()
1014 "Display a buffer in another window but don't select it.
1015 The buffer name is selected interactively by typing a substring.
1016 For details of keybindings, do `\\[describe-function] iswitchb'."
1017 (interactive)
1018 (setq iswitchb-method 'display)
1019 (iswitchb-entry))
1020
1021
1022
1023 ;;;###autoload
1024 (defun iswitchb-buffer-other-frame ()
1025 "Switch to another buffer and show it in another frame.
1026 The buffer name is selected interactively by typing a substring.
1027 For details of keybindings, do `\\[describe-function] iswitchb'."
1028 (interactive)
1029 (setq iswitchb-method 'otherframe)
1030 (iswitchb-entry))
1031
1032
1033
1034 (defun iswitchb-entry ()
1035 "Simply fall into `iswitchb' -- the main function."
1036 (iswitchb))
1037
1038
1039
1040
1041
1042 ;;; XEmacs hack for showing default buffer
1043
1044 ;; The first time we enter the minibuffer, Emacs puts up the default
1045 ;; buffer to switch to, but XEmacs doesnt -- presumably there is a
1046 ;; subtle difference in the two versions of post-command-hook. The
1047 ;; default is shown for both whenever we delete all of our text
1048 ;; though, indicating its just a problem the first time we enter the
1049 ;; function. To solve this, we use another entry hook for emacs to
1050 ;; show the default the first time we enter the minibuffer.
1051
1052 (defun iswitchb-init-Xemacs-trick ()
1053 "Display default buffer when first entering minibuffer.
1054 This is a hack for XEmacs, and should really be handled by `iswitchb-exhibit'."
1055 (if (iswitchb-entryfn-p)
1056 (progn
1057 (iswitchb-exhibit)
1058 (goto-char (point-min)))))
1059
1060
1061 ;; add this hook for XEmacs only.
1062 (if iswitchb-xemacs
1063 (add-hook 'iswitchb-minibuffer-setup-hook
1064 'iswitchb-init-Xemacs-trick))
1065
1066
1067 ;;; XEmacs / backspace key
1068 ;; For some reason, if the backspace key is pressed in xemacs, the
1069 ;; line gets confused, so I've added a simple key definition to make
1070 ;; backspace act like the normal delete key.
1071
1072 (defun iswitchb-xemacs-backspacekey ()
1073 "Bind backspace to `backward-delete-char'."
1074 (define-key iswitchb-mode-map '[backspace] 'backward-delete-char)
1075 (define-key iswitchb-mode-map '[(meta backspace)] 'backward-kill-word)
1076 )
1077
1078
1079 (if iswitchb-xemacs
1080 (add-hook 'iswitchb-define-mode-map-hook
1081 'iswitchb-xemacs-backspacekey))
1082
1083
1084
1085 ;;; ICOMPLETE TYPE CODE
1086
1087 (defun iswitchb-exhibit ()
1088 "Find matching buffers and display a list in the minibuffer.
1089 Copied from `icomplete-exhibit' with two changes:
1090 1. It prints a default buffer name when there is no text yet entered.
1091 2. It calls my completion routine rather than the standard completion."
1092
1093 (if iswitchb-use-mycompletion
1094 (let ((contents (buffer-substring (point-min)(point-max)))
1095 (buffer-undo-list t))
1096 (save-excursion
1097 (goto-char (point-max))
1098 ; Register the end of input, so we
1099 ; know where the extra stuff
1100 ; (match-status info) begins:
1101 (if (not (boundp 'iswitchb-eoinput))
1102 ;; In case it got wiped out by major mode business:
1103 (make-local-variable 'iswitchb-eoinput))
1104 (setq iswitchb-eoinput (point))
1105 ;; Update the list of matches
1106 (setq iswitchb-text contents)
1107 (iswitchb-set-matches)
1108 (setq iswitchb-rescan t)
1109 (iswitchb-set-common-completion)
1110
1111 ;; Insert the match-status information:
1112 (insert-string
1113 (iswitchb-completions
1114 contents
1115 minibuffer-completion-table
1116 minibuffer-completion-predicate
1117 (not minibuffer-completion-confirm)))
1118 ))))
1119
1120
1121
1122 (defun iswitchb-completions
1123 (name candidates predicate require-match)
1124 "Return the string that is displayed after the user's text.
1125 Modified from `icomplete-completions'."
1126
1127 (let ((comps iswitchb-matches)
1128 ; "-determined" - only one candidate
1129 (open-bracket-determined (if require-match "(" "["))
1130 (close-bracket-determined (if require-match ")" "]"))
1131 ;"-prospects" - more than one candidate
1132 (open-bracket-prospects "{")
1133 (close-bracket-prospects "}")
1134 first
1135 )
1136
1137 (if (and iswitchb-use-fonts comps)
1138 (progn
1139 (setq first (car comps))
1140 (setq first (format "%s" first))
1141 (put-text-property 0 (length first) 'face
1142 (if (eq (length comps) 1)
1143 'font-lock-comment-face
1144 'font-lock-function-name-face)
1145 first)
1146 (setq comps (cons first (cdr comps)))
1147 ))
1148
1149 (cond ((null comps) (format " %sNo match%s"
1150 open-bracket-determined
1151 close-bracket-determined))
1152
1153 ((null (cdr comps)) ;one match
1154 (concat (if (and (> (length (car comps))
1155 (length name)))
1156 (concat open-bracket-determined
1157 ;; when there is one match, show the
1158 ;; matching buffer name in full
1159 (car comps)
1160 close-bracket-determined)
1161 "")
1162 (if (not iswitchb-use-fonts) " [Matched]")
1163 ))
1164 (t ;multiple matches
1165 (let* (
1166 ;;(most (try-completion name candidates predicate))
1167 (most nil)
1168 (most-len (length most))
1169 most-is-exact
1170 first
1171 (alternatives
1172 (apply
1173 (function concat)
1174 (cdr (apply
1175 (function nconc)
1176 (mapcar '(lambda (com)
1177 (if (= (length com) most-len)
1178 ;; Most is one exact match,
1179 ;; note that and leave out
1180 ;; for later indication:
1181 (progn
1182 (setq most-is-exact t)
1183 ())
1184 (list ","
1185 (substring com
1186 most-len))))
1187 comps))))))
1188
1189 (concat
1190
1191 ;; put in common completion item -- what you get by
1192 ;; pressing tab
1193 (if (> (length iswitchb-common-match-string) (length name))
1194 (concat open-bracket-determined
1195 (substring iswitchb-common-match-string
1196 (length name))
1197 close-bracket-determined)
1198 )
1199 ;; end of partial matches...
1200
1201 ;; think this bit can be ignored.
1202 (and (> most-len (length name))
1203 (concat open-bracket-determined
1204 (substring most (length name))
1205 close-bracket-determined))
1206
1207 ;; list all alternatives
1208 open-bracket-prospects
1209 (if most-is-exact
1210 (concat "," alternatives)
1211 alternatives)
1212 close-bracket-prospects)))
1213 )))
1214
1215 (defun iswitchb-minibuffer-setup ()
1216 "Set up minibuffer for `iswitchb-buffer'.
1217 Copied from `icomplete-minibuffer-setup-hook'."
1218 (if (iswitchb-entryfn-p)
1219 (progn
1220
1221 (make-local-variable 'iswitchb-use-mycompletion)
1222 (setq iswitchb-use-mycompletion t)
1223 (make-local-hook 'pre-command-hook)
1224 (add-hook 'pre-command-hook
1225 'iswitchb-pre-command
1226 nil t)
1227 (make-local-hook 'post-command-hook)
1228 (add-hook 'post-command-hook
1229 'iswitchb-post-command
1230 nil t)
1231
1232 (run-hooks 'iswitchb-minibuffer-setup-hook)
1233 )
1234 ))
1235
1236
1237 (defun iswitchb-pre-command ()
1238 "Run before command in `iswitchb-buffer'."
1239 (iswitchb-tidy))
1240
1241
1242 (defun iswitchb-post-command ()
1243 "Run after command in `iswitchb-buffer'."
1244 (iswitchb-exhibit)
1245 )
1246
1247
1248
1249 (defun iswitchb-tidy ()
1250 "Remove completions display, if any, prior to new user input.
1251 Copied from `icomplete-tidy'."
1252
1253 (if (and (boundp 'iswitchb-eoinput)
1254 iswitchb-eoinput)
1255
1256 (if (> iswitchb-eoinput (point-max))
1257 ;; Oops, got rug pulled out from under us - reinit:
1258 (setq iswitchb-eoinput (point-max))
1259 (let ((buffer-undo-list buffer-undo-list )) ; prevent entry
1260 (delete-region iswitchb-eoinput (point-max))))
1261
1262 ;; Reestablish the local variable 'cause minibuffer-setup is weird:
1263 (make-local-variable 'iswitchb-eoinput)
1264 (setq iswitchb-eoinput 1)))
1265
1266
1267 (defun iswitchb-entryfn-p ()
1268 "Return non-nil if `this-command' shows we are using `iswitchb-buffer'."
1269 (and (symbolp this-command) ; ignore lambda functions
1270 (memq this-command
1271 '(iswitchb-buffer
1272 iswitchb-buffer-other-frame
1273 iswitchb-display-buffer
1274 iswitchb-buffer-other-window))))
1275
1276
1277
1278
1279 (defun iswitchb-summaries-to-end ()
1280 "Move the summaries to the end of the list.
1281 This is an example function which can be hooked on to
1282 `iswitchb-make-buflist-hook'. Any buffer matching the regexps
1283 `Summary' or `output\*$'are put to the end of the list."
1284 (let ((summaries (delq nil (mapcar
1285 (lambda (x)
1286 (if (or
1287 (string-match "Summary" x)
1288 (string-match "output\\*$" x))
1289 x))
1290 buflist)
1291 )))
1292
1293 (iswitchb-to-end summaries)))
1294
1295
1296
1297 ;;; HOOKS
1298 (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)
1299
1300 (provide 'iswitchb)
1301
1302 ;;; iswitchb.el ends here